nopaque.corpus_analysis.ReaderExtension = class ReaderExtension { name = 'Reader'; constructor(app) { this.app = app; this.data = {}; this.elements = { container: document.querySelector(`#corpus-analysis-reader-container`), corpus: document.querySelector(`#corpus-analysis-reader-corpus`), corpusPagination: document.querySelector(`#corpus-analysis-reader-corpus-pagination`), error: document.querySelector(`#corpus-analysis-reader-error`), progress: document.querySelector(`#corpus-analysis-reader-progress`), userInterfaceForm: document.querySelector(`#corpus-analysis-reader-user-interface-form`) }; this.settings = { perPage: parseInt(this.elements.userInterfaceForm['per-page'].value), textStyle: parseInt(this.elements.userInterfaceForm['text-style'].value), tokenRepresentation: this.elements.userInterfaceForm['token-representation'].value, pagination: { innerWindow: 5, outerWindow: 1 } } this.app.registerExtension(this); } 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.userInterfaceForm.addEventListener('submit', (event) => { event.preventDefault(); this.submitForm(); }); this.elements.userInterfaceForm.addEventListener('change', (event) => { if (event.target === this.elements.userInterfaceForm['per-page']) { this.settings.perPage = parseInt(this.elements.userInterfaceForm['per-page'].value); this.submitForm(); } if (event.target === this.elements.userInterfaceForm['text-style']) { this.settings.textStyle = parseInt(this.elements.userInterfaceForm['text-style'].value); this.setTextStyle(); } if (event.target === this.elements.userInterfaceForm['token-representation']) { this.settings.tokenRepresentation = this.elements.userInterfaceForm['token-representation'].value; this.setTokenRepresentation(); } }); // Load initial data await this.submitForm(); } clearCorpus() { // Destroy with .p-attr elements associated Materialize tooltips let pAttrElements = this.elements.corpus.querySelectorAll('.p-attr.tooltipped'); for (let pAttrElement of pAttrElements) { M.Tooltip.getInstance(pAttrElement)?.destroy(); } this.elements.corpus.innerHTML = `

searchNothing here...
No text available.

`.trim(); } renderCorpus() { this.clearCorpus(); let item = this.data.corpus.p.items[0]; this.elements.corpus.innerHTML += `

${this.cposRange2HTML(item[0], item[item.length - 1])}

`.trim(); this.setTextStyle(); this.setTokenRepresentation(); } clearCorpusPagination() { this.elements.corpusPagination.innerHTML = ''; this.elements.corpusPagination.classList.add('hide'); } renderCorpusPagination() { this.clearCorpusPagination(); if (this.data.corpus.p.pages === 0) {return;} let pageElement; // First page button. Disables first page button if on first page pageElement = nopaque.Utils.HTMLToElement( `
  • first_page
  • ` ); this.elements.corpusPagination.appendChild(pageElement); // Previous page button. Disables previous page button if on first page pageElement = nopaque.Utils.HTMLToElement( `
  • chevron_left
  • ` ); this.elements.corpusPagination.appendChild(pageElement); // First page as number. Hides first page button if on first page if (this.data.corpus.p.page > 6) { pageElement = nopaque.Utils.HTMLToElement( `
  • 1
  • ` ); this.elements.corpusPagination.appendChild(pageElement); pageElement = nopaque.Utils.HTMLToElement("
  • "); this.elements.corpusPagination.appendChild(pageElement); } // render page buttons (5 before and 5 after current page) for (let i = this.data.corpus.p.page - this.settings.pagination.innerWindow; i <= this.data.corpus.p.page; i++) { if (i <= 0) {continue;} pageElement = nopaque.Utils.HTMLToElement( `
  • ${i}
  • ` ); this.elements.corpusPagination.appendChild(pageElement); }; for (let i = this.data.corpus.p.page +1; i <= this.data.corpus.p.page + this.settings.pagination.innerWindow; i++) { if (i > this.data.corpus.p.pages) {break;} pageElement = nopaque.Utils.HTMLToElement( `
  • ${i}
  • ` ); this.elements.corpusPagination.appendChild(pageElement); }; // Last page as number. Hides last page button if on last page if (this.data.corpus.p.page < this.data.corpus.p.pages - 6) { pageElement = nopaque.Utils.HTMLToElement("
  • "); this.elements.corpusPagination.appendChild(pageElement); pageElement = nopaque.Utils.HTMLToElement( `
  • ${this.data.corpus.p.pages}
  • ` ); this.elements.corpusPagination.appendChild(pageElement); } // Next page button. Disables next page button if on last page pageElement = nopaque.Utils.HTMLToElement( `
  • chevron_right
  • ` ); this.elements.corpusPagination.appendChild(pageElement); // Last page button. Disables last page button if on last page pageElement = nopaque.Utils.HTMLToElement( `
  • last_page
  • ` ); this.elements.corpusPagination.appendChild(pageElement); for (let paginateTriggerElement of this.elements.corpusPagination.querySelectorAll('.pagination-trigger[data-target]')) { paginateTriggerElement.addEventListener('click', (event) => { event.preventDefault(); let page = parseInt(paginateTriggerElement.dataset.target); this.page(page); }); } this.elements.corpusPagination.classList.remove('hide'); } cposRange2HTML(firstCpos, lastCpos) { let html = ''; for (let cpos = firstCpos; cpos <= lastCpos; cpos++) { let prevPAttr = cpos > firstCpos ? this.data.corpus.p.lookups.cpos_lookup[cpos - 1] : null; let pAttr = this.data.corpus.p.lookups.cpos_lookup[cpos]; let nextPAttr = cpos < lastCpos ? this.data.corpus.p.lookups.cpos_lookup[cpos + 1] : null; let isEntityStart = 'ent' in pAttr && pAttr.ent !== prevPAttr?.ent; let isEntityEnd = 'ent' in pAttr && pAttr.ent !== nextPAttr?.ent; // Add a space before pAttr if (cpos !== firstCpos || pAttr.simple_pos !== 'PUNCT') {html += ' ';} // Add entity start if (isEntityStart) { html += ''; html += ``; } // Add pAttr html += ``; // Add entity end if (isEntityEnd) { html += ` ${this.data.corpus.p.lookups.ent_lookup[pAttr.ent].type}`; html += ''; html += ''; } } return html; } page(pageNum, callback) { if (this.data.corpus.p.page === pageNum && typeof callback === 'function') { callback(); return; } this.app.disableActionElements(); window.scrollTo(top); this.elements.progress.classList.remove('hide'); this.data.corpus.o.paginate(pageNum, this.settings.perPage) .then( (paginatedCorpus) => { this.data.corpus.p = paginatedCorpus; this.renderCorpus(); this.renderCorpusPagination(); this.elements.progress.classList.add('hide'); this.app.enableActionElements(); if (typeof callback === 'function') {callback();} } ) } setTextStyle() { if (this.settings.textStyle >= 0) { // Destroy with .p-attr elements associated Materialize tooltips for (let pAttrElement of this.elements.corpus.querySelectorAll('.p-attr.tooltipped')) { M.Tooltip.getInstance(pAttrElement)?.destroy(); } // Set basic styling on .p-attr elements for (let pAttrElement of this.elements.corpus.querySelectorAll('.p-attr')) { pAttrElement.setAttribute('class', 'p-attr'); } // Set basic styling on .s-attr[data-s-attr="ent_type"] elements for (let entElement of this.elements.corpus.querySelectorAll('.s-attr[data-s-attr="ent_type"]')) { entElement.querySelector('.ent-indicator').classList.add('hide'); // TODO: Check why this is here // entElement.removeAttribute('style'); entElement.setAttribute('class', 's-attr'); } } if (this.settings.textStyle >= 1) { // Set advanced styling on .s-attr[data-s-attr="ent_type"] elements for (let entElement of this.elements.corpus.querySelectorAll('.s-attr[data-s-attr="ent_type"]')) { entElement.classList.add('chip', 's-attr-color'); entElement.querySelector('.ent-indicator').classList.remove('hide'); } } if (this.settings.textStyle >= 2) { // Set advanced styling on .p-attr elements for (let pAttrElement of this.elements.corpus.querySelectorAll('.p-attr')) { pAttrElement.classList.add('chip', 'hoverable', 'tooltipped'); let cpos = pAttrElement.dataset.cpos; let pAttr = this.data.corpus.p.lookups.cpos_lookup[cpos]; let positionalPropertiesHTML = `

    Positional properties
    Token: ${cpos} `.trim(); let structuralPropertiesHTML = `

    Structural properties `.trim(); for (let [property, propertyValue] of Object.entries(pAttr)) { if (['lemma', 'ner', 'pos', 'simple_pos', 'word'].includes(property)) { if (propertyValue === 'None') {continue;} positionalPropertiesHTML += `
    subdirectory_arrow_right${property}: ${propertyValue}`; } else { structuralPropertiesHTML += `
    ${property}: ${propertyValue}`; if (!(`${property}_lookup` in this.data.corpus.p.lookups)) {continue;} for (let [subproperty, subpropertyValue] of Object.entries(this.data.corpus.p.lookups[`${property}_lookup`][propertyValue])) { if (subpropertyValue === 'NULL') {continue;} structuralPropertiesHTML += `
    subdirectory_arrow_right${subproperty}: ${subpropertyValue}` } } } positionalPropertiesHTML += '

    '; structuralPropertiesHTML += '

    '; M.Tooltip.init( pAttrElement, {html: positionalPropertiesHTML + structuralPropertiesHTML} ); } } } setTokenRepresentation() { for (let pAttrElement of this.elements.corpus.querySelectorAll('.p-attr')) { let pAttr = this.data.corpus.p.lookups.cpos_lookup[pAttrElement.dataset.cpos]; pAttrElement.innerText = pAttr[this.settings.tokenRepresentation]; } } }