diff --git a/app/static/js/CorpusAnalysis/CorpusAnalysisApp.js b/app/static/js/CorpusAnalysis/CorpusAnalysisApp.js index f35d3458..b7e860bd 100644 --- a/app/static/js/CorpusAnalysis/CorpusAnalysisApp.js +++ b/app/static/js/CorpusAnalysis/CorpusAnalysisApp.js @@ -26,22 +26,33 @@ class CorpusAnalysisApp { this.disableActionElements(); this.elements.m.initModal.open(); + const statusTextElement = this.elements.initModal.querySelector('.status-text'); + // Setup CQi over SocketIO connection and gather data from the CQPServer try { + statusTextElement.innerText = 'Creating CQi over SocketIO client...'; const cqiClient = new cqi.CQiClient('/cqi_over_sio'); + statusTextElement.innerText += ' Done'; + statusTextElement.innerHTML += '
Waiting for the CQP server...'; const response = await cqiClient.api.socket.emitWithAck('init', this.corpusId); if (response.code !== 200) {throw new Error();} + statusTextElement.innerText += ' Done'; + statusTextElement.innerHTML += '
Connecting to the CQP server...'; await cqiClient.connect('anonymous', ''); + statusTextElement.innerText += ' Done'; + statusTextElement.innerHTML += '
Building and receiving corpus data cache from the server (This may take a while)...'; const cqiCorpus = await cqiClient.corpora.get(`NOPAQUE-${this.corpusId.toUpperCase()}`); + statusTextElement.innerText += ' Done'; // TODO: Don't do this hgere await cqiCorpus.updateDb(); this.data.cqiClient = cqiClient; this.data.cqiCorpus = cqiCorpus; this.data.corpus = {o: cqiCorpus}; // legacy } catch (error) { - // TODO: Currently we can only handle CQiErrors here, - // but we should also handle other errors. - const errorString = `${error.code}: ${error.constructor.name}`; + let errorString = ''; + if ('code' in error) {errorString += `[${error.code}] `;} + errorString += `${error.constructor.name}`; + if ('description' in error) {errorString += `: ${error.description}`;} const errorsElement = this.elements.initModal.querySelector('.errors'); const progressElement = this.elements.initModal.querySelector('.progress'); errorsElement.innerText = errorString; @@ -51,7 +62,11 @@ class CorpusAnalysisApp { } // Initialize extensions - for (const extension of Object.values(this.extensions)) {extension.init();} + for (const extension of Object.values(this.extensions)) { + statusTextElement.innerHTML += `
Initializing extension ${extension.name}...`; + await extension.init(); + statusTextElement.innerText += ' Done' + } for (const extensionSelectorElement of this.elements.extensionCards.querySelectorAll('.extension-selector')) { extensionSelectorElement.addEventListener('click', () => { this.elements.m.extensionTabs.select(extensionSelectorElement.dataset.target); diff --git a/app/static/js/CorpusAnalysis/CorpusAnalysisConcordance.js b/app/static/js/CorpusAnalysis/CorpusAnalysisConcordance.js index e6c00e73..11ac9d2f 100644 --- a/app/static/js/CorpusAnalysis/CorpusAnalysisConcordance.js +++ b/app/static/js/CorpusAnalysis/CorpusAnalysisConcordance.js @@ -30,62 +30,60 @@ class CorpusAnalysisConcordance { this.app.registerExtension(this); } - init() { + async submitForm() { + this.app.disableActionElements(); + let query = this.elements.form.query.value.trim(); + let subcorpusName = this.elements.form['subcorpus-name'].value; + this.elements.error.innerText = ''; + this.elements.error.classList.add('hide'); + this.elements.progress.classList.remove('hide'); + try { + const subcorpus = {}; + subcorpus.q = query; + subcorpus.selectedItems = new Set(); + await this.data.corpus.o.query(subcorpusName, query); + if (subcorpusName !== 'Last') {this.data.subcorpora.Last = subcorpus;} + const cqiSubcorpus = await this.data.corpus.o.subcorpora.get(subcorpusName); + subcorpus.o = cqiSubcorpus; + const paginatedSubcorpus = await cqiSubcorpus.paginate(this.settings.context, 1, this.settings.perPage); + subcorpus.p = paginatedSubcorpus; + this.data.subcorpora[subcorpusName] = subcorpus; + this.settings.selectedSubcorpus = subcorpusName; + this.renderSubcorpusList(); + this.renderSubcorpusInfo(); + this.renderSubcorpusActions(); + this.renderSubcorpusItems(); + this.renderSubcorpusPagination(); + this.elements.progress.classList.add('hide'); + } catch (error) { + let errorString = ''; + if ('code' in error) {errorString += `[${error.code}] `;} + errorString += `${error.constructor.name}`; + this.elements.error.innerText = errorString; + this.elements.error.classList.remove('hide'); + app.flash(errorString, 'error'); + this.elements.progress.classList.add('hide'); + } + this.app.enableActionElements(); + } + + async init() { // Init data this.data.corpus = this.app.data.corpus; this.data.subcorpora = {}; // Add event listeners - this.elements.form.addEventListener('submit', event => { + this.elements.form.addEventListener('submit', (event) => { event.preventDefault(); - this.app.disableActionElements(); - let query = this.elements.form.query.value.trim(); - let subcorpusName = this.elements.form['subcorpus-name'].value; - this.elements.error.innerText = ''; - this.elements.error.classList.add('hide'); - this.elements.progress.classList.remove('hide'); - let subcorpus = {}; - this.data.corpus.o.query(subcorpusName, query) - .then((cqiStatus) => { - subcorpus.q = query; - subcorpus.selectedItems = new Set(); - if (subcorpusName !== 'Last') {this.data.subcorpora.Last = subcorpus;} - return this.data.corpus.o.subcorpora.get(subcorpusName); - }) - .then((cqiSubcorpus) => { - subcorpus.o = cqiSubcorpus; - return cqiSubcorpus.paginate(this.settings.context, 1, this.settings.perPage); - }) - .then( - (paginatedSubcorpus) => { - subcorpus.p = paginatedSubcorpus; - this.data.subcorpora[subcorpusName] = subcorpus; - this.settings.selectedSubcorpus = subcorpusName; - this.renderSubcorpusList(); - this.renderSubcorpusInfo(); - this.renderSubcorpusActions(); - this.renderSubcorpusItems(); - this.renderSubcorpusPagination(); - this.elements.progress.classList.add('hide'); - this.app.enableActionElements(); - }, - (cqiError) => { - let errorString = `${cqiError.code}: ${cqiError.constructor.name}`; - this.elements.error.innerText = errorString; - this.elements.error.classList.remove('hide'); - app.flash(errorString, 'error'); - this.elements.progress.classList.add('hide'); - this.app.enableActionElements(); - } - ); + this.submitForm(); }); - this.elements.form.addEventListener('change', event => { + this.elements.form.addEventListener('change', (event) => { if (event.target === this.elements.form['context']) { this.settings.context = parseInt(this.elements.form['context'].value); - this.elements.form.submit.click(); + this.submitForm(); } if (event.target === this.elements.form['per-page']) { this.settings.perPage = parseInt(this.elements.form['per-page'].value); - this.elements.form.submit.click(); + this.submitForm(); } if (event.target === this.elements.form['text-style']) { this.settings.textStyle = parseInt(this.elements.form['text-style'].value); @@ -161,7 +159,7 @@ class CorpusAnalysisConcordance { `.trim(); M.Tooltip.init(this.elements.subcorpusActions.querySelectorAll('.tooltipped')); - this.elements.subcorpusActions.querySelector('.subcorpus-export-trigger').addEventListener('click', event => { + this.elements.subcorpusActions.querySelector('.subcorpus-export-trigger').addEventListener('click', (event) => { event.preventDefault(); let subcorpus = this.data.subcorpora[this.settings.selectedSubcorpus]; let modalElementId = Utils.generateElementId('export-subcorpus-modal-'); @@ -218,7 +216,7 @@ class CorpusAnalysisConcordance { } } ); - exportButton.addEventListener('click', event => { + exportButton.addEventListener('click', (event) => { event.preventDefault(); this.app.disableActionElements(); this.elements.progress.classList.remove('hide'); @@ -240,7 +238,7 @@ class CorpusAnalysisConcordance { promise = subcorpus.o.export(50); } promise.then( - data => { + (data) => { let blob; if (exportFormat === 'csv') { let csvContent = 'sep=,\r\n'; @@ -286,7 +284,7 @@ class CorpusAnalysisConcordance { }); modal.open(); }); - this.elements.subcorpusActions.querySelector('.subcorpus-delete-trigger').addEventListener('click', event => { + this.elements.subcorpusActions.querySelector('.subcorpus-delete-trigger').addEventListener('click', (event) => { event.preventDefault(); let subcorpus = this.data.subcorpora[this.settings.selectedSubcorpus]; subcorpus.o.drop().then( @@ -362,7 +360,7 @@ class CorpusAnalysisConcordance { this.setTextStyle(); this.setTokenRepresentation(); for (let gotoReaderTriggerElement of this.elements.subcorpusItems.querySelectorAll('.goto-reader-trigger')) { - gotoReaderTriggerElement.addEventListener('click', event => { + gotoReaderTriggerElement.addEventListener('click', (event) => { event.preventDefault(); let corpusAnalysisReader = this.app.extensions.Reader; let itemId = parseInt(gotoReaderTriggerElement.closest('.item').dataset.id); @@ -384,7 +382,7 @@ class CorpusAnalysisConcordance { }); } for (let selectTriggerElement of this.elements.subcorpusItems.querySelectorAll('.select-trigger')) { - selectTriggerElement.addEventListener('click', event => { + selectTriggerElement.addEventListener('click', (event) => { event.preventDefault(); let itemElement = selectTriggerElement.closest('.item'); let itemId = parseInt(itemElement.dataset.id); @@ -446,14 +444,14 @@ class CorpusAnalysisConcordance { `.trim(); for (let paginationTriggerElement of this.elements.subcorpusPagination.querySelectorAll('.pagination-trigger[data-target]')) { - paginationTriggerElement.addEventListener('click', event => { + paginationTriggerElement.addEventListener('click', (event) => { event.preventDefault(); this.app.disableActionElements(); this.elements.progress.classList.remove('hide'); let page = parseInt(paginationTriggerElement.dataset.target); subcorpus.o.paginate(page, this.settings.perPage, this.settings.context) .then( - paginatedSubcorpus => { + (paginatedSubcorpus) => { subcorpus.p = paginatedSubcorpus; this.renderSubcorpusItems(); this.renderSubcorpusPagination(); diff --git a/app/static/js/CorpusAnalysis/CorpusAnalysisReader.js b/app/static/js/CorpusAnalysis/CorpusAnalysisReader.js index 3e73551d..eb63cae9 100644 --- a/app/static/js/CorpusAnalysis/CorpusAnalysisReader.js +++ b/app/static/js/CorpusAnalysis/CorpusAnalysisReader.js @@ -29,39 +29,42 @@ class CorpusAnalysisReader { this.app.registerExtension(this); } - init() { + async submitForm() { + this.app.disableActionElements(); + this.elements.error.innerText = ''; + this.elements.error.classList.add('hide'); + this.elements.progress.classList.remove('hide'); + try { + const paginatedCorpus = await this.data.corpus.o.paginate(1, this.settings.perPage); + this.data.corpus.p = paginatedCorpus; + this.renderCorpus(); + this.renderCorpusPagination(); + this.elements.progress.classList.add('hide'); + } catch (error) { + let errorString = ''; + if ('code' in error) {errorString += `[${error.code}] `;} + errorString += `${error.constructor.name}`; + if ('description' in error) {errorString += `: ${error.description}`;} + this.elements.error.innerText = errorString; + this.elements.error.classList.remove('hide'); + app.flash(errorString, 'error'); + this.elements.progress.classList.add('hide'); + } + this.app.enableActionElements(); + } + + async init() { // Init data this.data.corpus = this.app.data.corpus; // Add event listeners this.elements.form.addEventListener('submit', (event) => { event.preventDefault(); - this.app.disableActionElements(); - this.elements.error.innerText = ''; - this.elements.error.classList.add('hide'); - this.elements.progress.classList.remove('hide'); - this.data.corpus.o.paginate(1, this.settings.perPage) - .then( - (paginatedCorpus) => { - this.data.corpus.p = paginatedCorpus; - this.renderCorpus(); - this.renderCorpusPagination(); - this.elements.progress.classList.add('hide'); - this.app.enableActionElements(); - }, - (cqiError) => { - let errorString = `${cqiError.code}: ${cqiError.constructor.name}`; - this.elements.error.innerText = errorString; - this.elements.error.classList.remove('hide'); - app.flash(errorString, 'error'); - this.elements.progress.classList.add('hide'); - this.app.enableActionElements(); - } - ); + this.submitForm(); }); - this.elements.form.addEventListener('change', event => { + this.elements.form.addEventListener('change', (event) => { if (event.target === this.elements.form['per-page']) { this.settings.perPage = parseInt(this.elements.form['per-page'].value); - this.elements.form.submit.click(); + this.submitForm(); } if (event.target === this.elements.form['text-style']) { this.settings.textStyle = parseInt(this.elements.form['text-style'].value); @@ -73,7 +76,7 @@ class CorpusAnalysisReader { } }); // Load initial data - this.elements.form.submit.click(); + await this.submitForm(); } clearCorpus() { @@ -205,7 +208,7 @@ class CorpusAnalysisReader { this.elements.corpusPagination.appendChild(pageElement); for (let paginateTriggerElement of this.elements.corpusPagination.querySelectorAll('.pagination-trigger[data-target]')) { - paginateTriggerElement.addEventListener('click', event => { + paginateTriggerElement.addEventListener('click', (event) => { event.preventDefault(); let page = parseInt(paginateTriggerElement.dataset.target); this.page(page); diff --git a/app/static/js/CorpusAnalysis/CorpusAnalysisStaticVisualization.js b/app/static/js/CorpusAnalysis/CorpusAnalysisStaticVisualization.js index 81e1d466..0bd5b78e 100644 --- a/app/static/js/CorpusAnalysis/CorpusAnalysisStaticVisualization.js +++ b/app/static/js/CorpusAnalysis/CorpusAnalysisStaticVisualization.js @@ -13,7 +13,7 @@ class CorpusAnalysisStaticVisualization { this.app.registerExtension(this); } - init() { + async init() { // Init data this.data.corpus = this.app.data.corpus; this.renderGeneralCorpusInfo(); diff --git a/app/templates/corpora/analysis.html.j2 b/app/templates/corpora/analysis.html.j2 index 0e261d2c..bb9e4e68 100644 --- a/app/templates/corpora/analysis.html.j2 +++ b/app/templates/corpora/analysis.html.j2 @@ -53,6 +53,7 @@
+