diff --git a/web/app/corpora/events.py b/web/app/corpora/events.py index fa40115f9a88c65fc369d7dcb5cd2a65c2c0b0d8..58b2d9a09fd9286ebd6b788880039bbdb1eea69e 100644 --- a/web/app/corpora/events.py +++ b/web/app/corpora/events.py @@ -129,22 +129,31 @@ def corpus_analysis_query(query): @socketio_login_required def corpus_analysis_inspect_match(payload): type = payload['type'] - data_index = payload["data_index"] + data_indexes = payload['data_indexes'] + first_cpos = payload['first_cpos'] + last_cpos = payload['last_cpos'] client = corpus_analysis_clients.get(request.sid) if client is None: response = {'code': 424, 'desc': 'No client found for this session', 'msg': 'Failed Dependency', 'type': type, - 'data_index': data_index} + 'data_indexes': data_indexes} socketio.emit('corpus_analysis_inspect_match', response, room=request.sid) return try: corpus = client.corpora.get('CORPUS') s = corpus.structural_attributes.get('s') - payload = s.export(payload['first_cpos'], payload['last_cpos'], - context=10) + payload = {} + payload['matches'] = [] + payload['cpos_lookup'] = {} + payload['text_lookup'] = {} + for index, f_cpos, l_cpos in zip(data_indexes, first_cpos, last_cpos): + tmp_match = s.export(f_cpos, l_cpos, context=10) + payload['matches'].append(tmp_match['matches'][0]) + payload['cpos_lookup'].update(tmp_match['cpos_lookup']) + payload['text_lookup'].update(tmp_match['text_lookup']) payload['cpos_ranges'] = True except cqi.errors.CQiException as e: payload = {'code': e.code, 'desc': e.description, 'msg': e.name} @@ -153,14 +162,14 @@ def corpus_analysis_inspect_match(payload): 'msg': 'Internal Server Error', 'payload': payload, 'type': type, - 'data_index': data_index} + 'data_indexes': data_indexes} else: response = {'code': 200, 'desc': None, 'msg': 'OK', 'payload': payload, 'type': type, - 'data_index': data_index} + 'data_indexes': data_indexes} socketio.emit('corpus_analysis_inspect_match', response, room=request.sid) diff --git a/web/app/static/css/nopaque.css b/web/app/static/css/nopaque.css index 24027647a79a3ce60683456374a2069f00b8d4a2..57173da1bb902966ee4c5a67467ead9c0db10131 100644 --- a/web/app/static/css/nopaque.css +++ b/web/app/static/css/nopaque.css @@ -19,6 +19,15 @@ main { font-weight: bold; } +/* preloader circle in the size of a button icon */ +.button-icon-spinner { + bottom: -8px !important; + right: -16px !important; + margin-right: 12px !important; + width: 19.5px !important; + height: 19.5px !important; +} + /* CSS for clickable th elements in tables. Needed for sortable table data with list js. On click on th header elements will be sorted accordingly. Also a caret indicator will show up how the column is sorted right now.; */ diff --git a/web/app/static/js/nopaque.CorpusAnalysisClient.js b/web/app/static/js/nopaque.CorpusAnalysisClient.js index 31db4e84659f6d8f83f74ed9f24650d4bc1c606c..f96086e1779f3584495d4383e6c8b1ace3676cfb 100644 --- a/web/app/static/js/nopaque.CorpusAnalysisClient.js +++ b/web/app/static/js/nopaque.CorpusAnalysisClient.js @@ -88,16 +88,14 @@ class CorpusAnalysisClient { // inspect callback handeling based on type socket.on("corpus_analysis_inspect_match", (response) => { + console.log(response); if (response.type === "inspect") { if (this.callbacks.query_match_context != undefined) { this.callbacks.query_match_context(response); } - } else if (response.type === "sub-subcorpus"){ - if (this.callbacks.show_sub_subcorpus_choices != undefined) { - this.callbacks.show_sub_subcorpus_choices(response); - } - if (this.callbacks.save_sub_subcorpus_choices != undefined) { - this.callbacks.save_sub_subcorpus_choices(response); + } else if (response.type === "sub-results"){ + if (this.callbacks.save_sub_results_choices != undefined) { + this.callbacks.save_sub_results_choices(response); } } }); diff --git a/web/app/static/js/nopaque.Results.js b/web/app/static/js/nopaque.Results.js index b592973f9007ed7e7e3057693d586196fbfaa9ef..8fb55db48fc1a87f780a2df87ed27949fb971d52 100644 --- a/web/app/static/js/nopaque.Results.js +++ b/web/app/static/js/nopaque.Results.js @@ -3,6 +3,7 @@ class Results { this.data = data; this.jsList = jsList; this.metaData = metaData + this.subResultsData = new Data(); } clearAll() { @@ -10,7 +11,9 @@ class Results { this.jsList.update(); this.data.init(); this.metaData.init(); + this.subResultsData.init(); } + } @@ -22,11 +25,16 @@ class Data { this["cpos_lookup"] = {}; // object contains all this key value pair this["text_lookup"] = {}; // same as above for all text ids this["match_count"] = matchCount; - this["corpus_type"] = "subcorpus" + this["corpus_type"] = "results"; + this["query"] = ""; } - addData(jsonData) { - Object.assign(this, jsonData); + addData(jsonData, key=null) { + if (key !== null) { + Object.assign(this[key], jsonData); + } else if (key === null) { + Object.assign(this, jsonData) + } } // get query as string from form Element @@ -80,6 +88,19 @@ class Data { // start actual download this.download(downloadElement, dataStr, resultFilename, "text/json", ".json") } + + // createSubResultsData from subResultsTmpData + createSubResultsData() { + let tmp = [...results.jsList.addToSubResultsIdsToShow].sort(function(a, b){return a-b}); + let dataIndexes = []; + tmp.forEach((index) => dataIndexes.push(index - 1)); + console.log(dataIndexes); + results.jsList.getMatchWithContext(dataIndexes, "sub-results"); + // TODO: save incoming matche infos with saveSubResultsChoices. + // TODO: trigger this function on dl btn click and seta flag that it has run to avoid double execution + // also set this flag to false if addToSubResultsIdsToShow has been altered + } + } class MetaData { diff --git a/web/app/static/js/nopaque.callbacks.js b/web/app/static/js/nopaque.callbacks.js index cbf8cf0b22e4fbe83a6c1d8b79627c68a67b02d8..9f849735dfc24132d9836f7147db9ec77b04bdd4 100644 --- a/web/app/static/js/nopaque.callbacks.js +++ b/web/app/static/js/nopaque.callbacks.js @@ -3,16 +3,34 @@ function recvMetaData(payload) { console.log(results.metaData); } -function saveSubSubcorpusChoices(payload) { - console.log("SAVE"); - console.log(payload); +function saveSubResultsChoices(response) { + console.log("Recieve match with context"); + results.subResultsData.init(); + results.subResultsData.matches.push(...response.payload.matches); + results.subResultsData.addData(response.payload.cpos_lookup, "cpos_lookup"); + results.subResultsData.addData(response.payload.text_lookup, "text_lookup"); + results.subResultsData.addData(results.metaData); + results.subResultsData.query = results.data.query; + results.subResultsData.corpus_type = "sub-results"; + results.subResultsData.match_count = [...response.payload.matches].length; + results.subResultsData.cpos_ranges = response.payload.cpos_ranges; + console.log(results.subResultsData); + subResultsCreateElement.getElementsByClassName("button-icon-spinner")[0].remove(); + subResultsCreateElement.getElementsByTagName("i")[0].classList.remove("hide"); + subResultsCreateElement.firstElementChild.classList.add("disabled"); + subResultsExportElement.classList.remove("disabled"); } function querySetup(payload) { // This is called when a query was successfull // some hiding and resetting + let textarea = subResultsIdListElement.getElementsByTagName("textarea")[0]; + textarea.innerText = ""; + M.textareaAutoResize(textarea); + results.jsList.addToSubResultsStatus = {}; + results.jsList.addToSubResultsIdsToShow = new Set(); queryResultsExportElement.classList.add("disabled"); - addToSubSubcorpusElement.setAttribute("disabled", ""); + addToSubResultsElement.setAttribute("disabled", ""); queryResultsDeterminateElement.style.width = "0%"; queryResultsProgressElement.classList.remove("hide"); queryResultsUserFeedbackElement.classList.remove("hide"); @@ -72,11 +90,11 @@ function queryRenderResults(payload) { queryResultsProgressElement.classList.add("hide"); queryResultsUserFeedbackElement.classList.add("hide"); queryResultsExportElement.classList.remove("disabled"); - addToSubSubcorpusElement.removeAttribute("disabled"); + addToSubResultsElement.removeAttribute("disabled"); results.jsList.activateInspect(); - // inital expert mode check and sub subcorpus activation - if (addToSubSubcorpusElement.checked) { - results.jsList.activateAddToSubSubcorpus(); + // inital expert mode check and sub results activation + if (addToSubResultsElement.checked) { + results.jsList.activateAddToSubResults(); } if (expertModeSwitchElement.checked) { results.jsList.expertModeOn("query-display"); diff --git a/web/app/static/js/nopaque.lists.js b/web/app/static/js/nopaque.lists.js index 10f446b2a35556301ec7fd523f76a8a5630fbe9c..150c6c781b44e2d3eaacccd6cc535e1a653b9709 100644 --- a/web/app/static/js/nopaque.lists.js +++ b/web/app/static/js/nopaque.lists.js @@ -134,7 +134,8 @@ class ResultsList extends List { this.currentExpertTokenElements = {}; // all token elements which have added // classes like chip and hoverable for expert view. Collected //here to delete later on - this.addToSubSubcorpuStatus = {}; + this.addToSubResultsStatus = {}; + this.addToSubResultsIdsToShow = new Set(); } // handels interactionElements during a pagination navigation @@ -178,60 +179,74 @@ class ResultsList extends List { return displayOptionsData } - // ###### Functions to add one match to a sub-subcorpus ###### + // ###### Functions to add one match to a sub-results ###### // activate add button - activateAddToSubSubcorpus() { - let addToSubSubcorpusBtnElements = document.getElementsByClassName("add"); - for (let addToSubSubcorpusBtn of addToSubSubcorpusBtnElements) { - addToSubSubcorpusBtn.classList.remove("hide"); + activateAddToSubResults() { + subResultsIdListElement.classList.remove("hide"); + subResultsCreateElement.classList.remove("hide"); + let addToSubResultsBtnElements = document.getElementsByClassName("add"); + for (let addToSubResultsBtn of addToSubResultsBtnElements) { + addToSubResultsBtn.classList.remove("hide"); } } // deactivate add button - deactivateAddToSubSubcorpus() { - let addToSubSubcorpusBtnElements = document.getElementsByClassName("add"); - for (let addToSubSubcorpusBtn of addToSubSubcorpusBtnElements) { - addToSubSubcorpusBtn.classList.add("hide"); + deactivateAddToSubResults() { + subResultsIdListElement.classList.add("hide"); + subResultsCreateElement.classList.add("hide"); + let addToSubResultsBtnElements = document.getElementsByClassName("add"); + for (let addToSubResultsBtn of addToSubResultsBtnElements) { + addToSubResultsBtn.classList.add("hide"); } } - // add match on click to a SubSubcorpus - addToSubSubcorpus(dataIndex) { - if (!this.addToSubSubcorpuStatus[dataIndex] - || this.addToSubSubcorpuStatus === undefined) { + // add match id on click to a List of marked matches for SubSubcorpora + // remove match id on click from same list + addToSubResults(dataIndex) { + let textarea = subResultsIdListElement.getElementsByTagName("textarea")[0] + if (!this.addToSubResultsStatus[dataIndex] + || this.addToSubResultsStatus === undefined) { // add button is activated - nopaque.flash(`[Match ${dataIndex + 1}] Marked for Sub-Subcorpus!`); + nopaque.flash(`[Match ${dataIndex + 1}] Marked for Sub-Results!`); event.target.classList.remove("grey"); event.target.classList.add("green"); event.target.innerText = "check"; - this.addToSubSubcorpuStatus[dataIndex] = true; - this.getMatchWithContext(dataIndex, "sub-subcorpus"); - } else if (this.addToSubSubcorpuStatus[dataIndex]) { + this.addToSubResultsStatus[dataIndex] = true; + this.addToSubResultsIdsToShow.add(dataIndex + 1); + textarea.innerText = [...this.addToSubResultsIdsToShow].sort(function(a, b){return a-b}).join(", "); + M.textareaAutoResize(textarea); + } else if (this.addToSubResultsStatus[dataIndex]) { // add button is deactivated - nopaque.flash(`[Match ${dataIndex + 1}] Unmarked for Sub-Subcorpus!`); + nopaque.flash(`[Match ${dataIndex + 1}] Unmarked for Sub-results!`); event.target.classList.remove("green"); event.target.classList.add("grey"); event.target.innerText = "add"; - this.addToSubSubcorpuStatus[dataIndex] = false; + this.addToSubResultsStatus[dataIndex] = false; + this.addToSubResultsIdsToShow.delete(dataIndex + 1); + textarea.innerText = [...this.addToSubResultsIdsToShow].sort(function(a, b){return a-b}).join(", "); + M.textareaAutoResize(textarea); } + if ([...this.addToSubResultsIdsToShow].length > 0) { + subResultsCreateElement.firstElementChild.classList.remove("disabled"); + } else if ([...this.addToSubResultsIdsToShow].length === 0) { + subResultsCreateElement.firstElementChild.classList.add("disabled"); + } + subResultsExportElement.classList.add("disabled"); } - // handels incoming match info from socket on event - showSubSubcorpusChoices(response) { - console.log("SHOW"); - console.log(response.data_index); - } - - // gets full info for one match - getMatchWithContext(dataIndex, type) { - this.contextId = dataIndex; - let contextResultsElement; - contextResultsElement = document.getElementById("context-results"); - contextResultsElement.innerHTML = ""; // clear it from old inspects + // triggers emit to get full match context from server for a number of + // matches identified by their data_index + getMatchWithContext(dataIndexes, type) { + let tmp_first_cpos = []; + let tmp_last_cpos = []; + for (let dataIndex of dataIndexes) { + tmp_first_cpos.push(results.data.matches[dataIndex].c[0]); + tmp_last_cpos.push(results.data.matches[dataIndex].c[1]); + } nopaque.socket.emit("corpus_analysis_inspect_match", { type: type, - data_index: dataIndex, - first_cpos: results.data.matches[dataIndex].c[0], - last_cpos: results.data.matches[dataIndex].c[1], + data_indexes: dataIndexes, + first_cpos: tmp_first_cpos, + last_cpos: tmp_last_cpos, } ); } @@ -250,10 +265,22 @@ class ResultsList extends List { } } - //gets result cpos infos for one dataIndex to send back to the server + // gets result cpos infos for one dataIndex (list of length 1) to send back to + // the server inspect(dataIndex, type) { + this.contextId = dataIndex[0]; + let contextResultsElement; + contextResultsElement = document.getElementById("context-results"); + contextResultsElement.innerHTML = ""; // clear it from old inspects this.getMatchWithContext(dataIndex, type); contextModal.open(); + let css = `margin-right: 10px;` + let classes = `btn-floating btn waves-effect` + + `waves-light grey right` + addToSubResultsFromInspectElement = document.createElement("a"); + addToSubResultsFromInspectElement.setAttribute("class", classes + `add`); + addToSubResultsFromInspectElement.innerHTML = '<i class="material-icons">add</i>'; + addToSubResultsFromInspectElement.onclick= (event) => {this.addToSubResults(dataIndex)}; } // create Element from HTML String helper function @@ -286,11 +313,13 @@ class ResultsList extends List { let uniqueS; this.contextData = response.payload; + this.contextData["cpos_ranges"] = response.payload.cpos_ranges; this.contextData["query"] = results.data.query; this.contextData["context_id"] = this.contextId; this.contextData["match_count"] = this.contextData.matches.length - this.contextData["corpus_type"] = "sub-subcorpus" + this.contextData["corpus_type"] = "inspect-result" Object.assign(this.contextData, results.metaData); + console.log(this.contextData); contextResultsElement = document.getElementById("context-results"); modalExpertModeSwitchElement = document.getElementById("inspect-display-options-form-expert_mode_inspect"); highlightSentencesSwitchElement = document.getElementById("inspect-display-options-form-highlight_sentences"); @@ -595,7 +624,7 @@ class ResultsList extends List { } createResultRowElement(item, chunk) { - let addToSubSubcorpusBtn; + let addToSubResultsBtn; let c; let cCellElement; let cpos; @@ -663,16 +692,16 @@ class ResultsList extends List { ); inspectBtn.setAttribute("style", css) inspectBtn.innerHTML = '<i class="material-icons">search</i>'; - inspectBtn.onclick = () => {this.inspect(values.index, "inspect")}; - // # add btn to add matches to sub-subcorpus. hidden per default - addToSubSubcorpusBtn = document.createElement("a"); - addToSubSubcorpusBtn.setAttribute("class", classes + ` hide add` + inspectBtn.onclick = () => {this.inspect([values.index], "inspect")}; + // # add btn to add matches to sub-results. hidden per default + addToSubResultsBtn = document.createElement("a"); + addToSubResultsBtn.setAttribute("class", classes + ` hide add` ); - addToSubSubcorpusBtn.setAttribute("style", css) - addToSubSubcorpusBtn.innerHTML = '<i class="material-icons">add</i>'; - addToSubSubcorpusBtn.onclick= (event) => {this.addToSubSubcorpus(values.index)} + addToSubResultsBtn.setAttribute("style", css) + addToSubResultsBtn.innerHTML = '<i class="material-icons">add</i>'; + addToSubResultsBtn.onclick= (event) => {this.addToSubResults(values.index)} cCellElement.appendChild(inspectBtn); - cCellElement.appendChild(addToSubSubcorpusBtn); + cCellElement.appendChild(addToSubResultsBtn); // add text titles at front as first td of one row textTitlesCellElement.innerText = [...textTitles].join(", "); matchRowElement.insertAdjacentHTML("afterbegin", textTitlesCellElement.outerHTML); diff --git a/web/app/templates/corpora/analyse_corpus.html.j2 b/web/app/templates/corpora/analyse_corpus.html.j2 index f67455876081573d58813573175cef3f370d8a82..7fa96309cede3bf1448a30abb31d4aff164f6297 100644 --- a/web/app/templates/corpora/analyse_corpus.html.j2 +++ b/web/app/templates/corpora/analyse_corpus.html.j2 @@ -74,43 +74,109 @@ </div> <div class="col s12 m9 l9" id="actions-and-tools"> <div class="row section"> - <div class="col" id="Export"> + <div class="col s12 m3 l3" id="export"> <h6 style="margin-top: 0px;">Export</h6> <div class="divider" style="margin-bottom: 10px;"></div> - <button id="query-results-export" - class="waves-effect - waves-light - btn-flat - disabled" - type="submit">Export Results - <i class="material-icons left">file_download</i> - </button> + <div class="row"> + <div class="col"> + <button id="query-results-export" + class="waves-effect + waves-light + btn-flat + disabled" + type="submit">Export Results + <i class="material-icons left">file_download</i> + </button> + </div> + <div class="col"> + <button id="sub-results-export" + class="waves-effect + waves-light + btn-flat + disabled" + type="submit">Export Sub-Results + <i class="material-icons left">file_download</i> + </button> + </div> + </div> </div> - <div class="col" id="Create"> + <div class="col s12 m3 l3" id="create"> <h6 style="margin-top: 0px;">Create</h6> <div class="divider" style="margin-bottom: 10px;"></div> - <div class="switch"> - Sub-Subcorpus creation: - <label> - Off - <input disabled - type="checkbox" - id="add-to-sub-subcorpus"> - <span class="lever"></span> - On - </label> + <div class="row"> + <div class="col"> + <div class="switch"> + Sub-Results creation: + <label> + Off + <input disabled + type="checkbox" + id="add-to-sub-results"> + <span class="lever"></span> + On + </label> + </div> + </div> + <div class="col hide" id="sub-results-match-ids-div"> + <div class="input-field"> + <p>Marked matches for Sub-Results:</p> + <textarea id="sub-results-match-ids" + class="materialize-textarea" + disabled> + </textarea> + </div> + </div> + <div class="col hide" id="sub-results-create-div"> + <button class="waves-effect + waves-light + btn-flat + disabled" + type="submit">Create + <i class="material-icons left">build</i> + </button> + </div> </div> </div> - <div class="col" id="Display"> + <div class="col s12 m3 l3" id="display"> <h6 style="margin-top: 0px;">Display</h6> <div class="divider" style="margin-bottom: 10px;"></div> - <form id="display-options-form"> - {{ M.render_field(display_options_form.results_per_page, - material_icon='format_list_numbered') }} - {{ M.render_field(display_options_form.result_context, - material_icon='short_text') }} - {{ M.render_field(display_options_form.expert_mode) }} - </form> + <div class="row"> + <div class="col"> + <form id="display-options-form"> + {{ M.render_field(display_options_form.results_per_page, + material_icon='format_list_numbered') }} + {{ M.render_field(display_options_form.result_context, + material_icon='short_text') }} + {{ M.render_field(display_options_form.expert_mode) }} + </form> + </div> + </div> + </div> + <div class="col s12 m3 l3" id="anlysis"> + <h6 style="margin-top: 0px;">Analysis</h6> + <div class="divider" style="margin-bottom: 10px;"></div> + <div class="row"> + <div class="col"> + <button id="placeholder1" + class="waves-effect + waves-light + btn-flat + disabled" + type="submit">Action One + <i class="material-icons left">cloud</i> + </button> + </div> + <div class="col"> + <button id="placeholder2" + class="waves-effect + waves-light + btn-flat + disabled" + type="submit">Action Two + <i class="material-icons left">add</i> + </button> + </div> + </div> </div> </div> </div> @@ -254,6 +320,11 @@ </div> </div> </li> + <li class="collection-item"> + Add to Sub Results + <div class="secondary-content" id="add-to-sub-results-from-inspect"> + </div> + </li> </ul> </form> </div> @@ -265,7 +336,7 @@ </div> <div class="modal-footer"> <a id="inspect-download-context" class="left waves-effect waves-light btn"> - Export Context + Export Single Context <i class="material-icons right">file_download</i> </a> <a href="#!" class="modal-close waves-effect waves-light red btn">Close</a> @@ -283,7 +354,7 @@ </script> <script> // ###### Defining global variables used in other functions ###### - var addToSubSubcorpusElement; // Button to start adding matches to sub-subcorpus + var addToSubResultsElement; // Button to start adding matches to sub-results var client; // CorpusAnalysisClient first undefined on DOMContentLoaded defined var collapsibleElements; // All collapsibleElements on this page var contextModal; // Modal to open on inspect for further match context @@ -305,6 +376,10 @@ var textLookupCountElement // Nr of texts the matches occured in will be shown in this element var interactionElements; // Interaction elements and their parameters var textTitlesElement; // matched text titles + var subResultsIdListElement; // list showing marked matches for sub corpus creation + var subResultsExportElement; // button to download sub results + var subResultsCreateElement; // if presses sub results will be created from ids + var addToSubResultsFromInspectElement; // button in inspect mdoal to add this match to the sub results // ###### Defining local scope variables ###### let contextPerItemElement; // Form Element for display option @@ -324,7 +399,7 @@ // ###### Initialize variables ###### client = undefined; - addToSubSubcorpusElement = document.getElementById("add-to-sub-subcorpus"); + addToSubResultsElement = document.getElementById("add-to-sub-results"); collapsibleElements = document.querySelector('.collapsible.expandable'); contextModal = document.getElementById("context-modal"); contextPerItemElement = document.getElementById("display-options-form-result_context"); @@ -347,6 +422,10 @@ receivedMatchCountElement = document.getElementById("received-match-count"); textLookupCountElement = document.getElementById("text-lookup-count"); textTitlesElement = document.getElementById("text-titles"); + subResultsIdListElement = document.getElementById("sub-results-match-ids-div"); + subResultsExportElement = document.getElementById("sub-results-export"); + subResultsCreateElement = document.getElementById("sub-results-create-div"); + addToSubResultsFromInspectElement = document.getElementById("add-to-sub-results-from-inspect"); // ###### js list options and intialization ###### displayOptionsData = ResultsList.getDisplayOptions(displayOptionsFormElement); @@ -405,11 +484,8 @@ client.setCallback("query_match_context", (payload) => { results.jsList.showMatchContext(payload); }); - client.setCallback("show_sub_subcorpus_choices", (payload) => { - results.jsList.showSubSubcorpusChoices(payload); - }); - client.setCallback("save_sub_subcorpus_choices", (payload) => { - saveSubSubcorpusChoices(payload); + client.setCallback("save_sub_results_choices", (payload) => { + saveSubResultsChoices(payload); }); // Trigger corpus analysis initialization on server side @@ -460,12 +536,12 @@ results.jsList, ["query-display"]) - let subSubcorpusInteraction = new InteractionElement("add-to-sub-subcorpus"); - subSubcorpusInteraction.setCallback("on", - results.jsList.activateAddToSubSubcorpus, + let subResultsInteraction = new InteractionElement("add-to-sub-results"); + subResultsInteraction.setCallback("on", + results.jsList.activateAddToSubResults, results.jsList); - subSubcorpusInteraction.setCallback("off", - results.jsList.deactivateAddToSubSubcorpus, + subResultsInteraction.setCallback("off", + results.jsList.deactivateAddToSubResults, results.jsList); let activateInspectInteraction = new InteractionElement("inspect", @@ -479,12 +555,12 @@ changeContextInteraction.setCallback("noCheck", results.jsList.changeContext, results.jsList) - interactionElements.push(expertModeInteraction, subSubcorpusInteraction, activateInspectInteraction, changeContextInteraction); + interactionElements.push(expertModeInteraction, subResultsInteraction, activateInspectInteraction, changeContextInteraction); // eventListener if pagination is used to apply new context size to new page // and also activate inspect match if progress is 100 - // also adds more interaction buttons like add to subcorpus + // also adds more interaction buttons like add to sub results for (let element of paginationElements) { element.addEventListener("click", (event) => { results.jsList.pageChangeEventInteractionHandler(interactionElements); @@ -516,15 +592,49 @@ // Add onclick to open download modal when Export Results button is pressed queryResultsExportElement.onclick = () => { exportModal.open(); + // add onclick to download JSON button and download the file + downloadResultsJSONElement = document.getElementById("download-results-json") + downloadResultsJSONElement.onclick = () => { + let filename = results.data.createDownloadFilename("matches"); + results.data.addData(results.metaData); + results.data.downloadJSONRessource(filename, results.data, + downloadResultsJSONElement + )}; + } + + // create sub results on click from shown marked match ids + subResultsCreateElement.onclick = () => { + subResultsCreateElement.getElementsByTagName("i")[0].classList.add("hide"); + let html = ` + <div class="preloader-wrapper button-icon-spinner small active"> + <div class="spinner-layer spinner-green-only"> + <div class="circle-clipper left"> + <div class="circle"></div> + </div><div class="gap-patch"> + <div class="circle"></div> + </div><div class="circle-clipper right"> + <div class="circle"></div> + </div> + </div> + </div> + ` + subResultsCreateElement.insertAdjacentHTML("afterbegin", html); + results.data.createSubResultsData(); + } + + // Add onclick to open download modal when sub results button is pressed + subResultsExportElement.onclick = () => { + exportModal.open(); + console.log(results.subResultsData); + // add onclick to download JSON button and download the file + downloadResultsJSONElement = document.getElementById("download-results-json") + downloadResultsJSONElement.onclick = () => { + let filename = results.data.createDownloadFilename("matches-sub-results"); + results.subResultsData.downloadJSONRessource(filename, + results.subResultsData, + downloadResultsJSONElement + )}; } - // add onclick to download JSON button and download the file - downloadResultsJSONElement = document.getElementById("download-results-json") - downloadResultsJSONElement.onclick = () => { - let filename = results.data.createDownloadFilename("matches"); - results.data.addData(results.metaData); - results.data.downloadJSONRessource(filename, results.data, - downloadResultsJSONElement - )}; // add onclick to download JSON button and download the file downloadInspectContextElement = document.getElementById("inspect-download-context")