alessandro trinca tornidor
commited on
Commit
·
0c4660b
1
Parent(s):
7a541c8
feat: UI change, now it shows some text around the selected word
Browse files- static/index-dark.css +4 -1
- static/index.css +4 -1
- static/index.js +94 -22
static/index-dark.css
CHANGED
@@ -9,7 +9,7 @@
|
|
9 |
text-align: left;
|
10 |
font-weight: bold;
|
11 |
}
|
12 |
-
#words-frequency > table > thead > tr > td, #words-frequency > table > tbody > tr > td {
|
13 |
padding-left: 10px;
|
14 |
padding-right: 10px;
|
15 |
}
|
@@ -17,6 +17,9 @@
|
|
17 |
height: 30px;
|
18 |
width: 100%;
|
19 |
}
|
|
|
|
|
|
|
20 |
.display-none {
|
21 |
display: none;
|
22 |
}
|
|
|
9 |
text-align: left;
|
10 |
font-weight: bold;
|
11 |
}
|
12 |
+
#words-frequency > div > table > thead > tr > td, #words-frequency > div > table > tbody > tr > td {
|
13 |
padding-left: 10px;
|
14 |
padding-right: 10px;
|
15 |
}
|
|
|
17 |
height: 30px;
|
18 |
width: 100%;
|
19 |
}
|
20 |
+
.font-weight-bold {
|
21 |
+
font-weight: bolder;
|
22 |
+
}
|
23 |
.display-none {
|
24 |
display: none;
|
25 |
}
|
static/index.css
CHANGED
@@ -16,10 +16,13 @@
|
|
16 |
text-align: left;
|
17 |
font-weight: bold;
|
18 |
}
|
19 |
-
#words-frequency > table > thead > tr > td, #words-frequency > table > tbody > tr > td {
|
20 |
padding-left: 10px;
|
21 |
padding-right: 10px;
|
22 |
}
|
|
|
|
|
|
|
23 |
.display-none {
|
24 |
display: none;
|
25 |
}
|
|
|
16 |
text-align: left;
|
17 |
font-weight: bold;
|
18 |
}
|
19 |
+
#words-frequency > div > table > thead > tr > td, #words-frequency > div > table > tbody > tr > td {
|
20 |
padding-left: 10px;
|
21 |
padding-right: 10px;
|
22 |
}
|
23 |
+
.font-weight-bold {
|
24 |
+
font-weight: bolder;
|
25 |
+
}
|
26 |
.display-none {
|
27 |
display: none;
|
28 |
}
|
static/index.js
CHANGED
@@ -1,7 +1,8 @@
|
|
1 |
const wordsFrequencyTableTitleText = "Words Frequency Stats"
|
2 |
let wfo = {
|
3 |
"words_frequency": {},
|
4 |
-
"nTotalRows": null
|
|
|
5 |
}
|
6 |
const editorFieldLabel = "editor"
|
7 |
const remoteWebServer = "http://localhost:7860"
|
@@ -42,7 +43,7 @@ const wordsFrequencyAnalyzers = {
|
|
42 |
let freq = bodyResponseJson["words_frequency"]
|
43 |
let nTotalRows = bodyResponseJson["n_total_rows"]
|
44 |
console.log(`wordsFrequencyAnalyzers::nTotalRows: '${nTotalRows}'`)
|
45 |
-
populateWordsFrequencyTables(freq, nTotalRows)
|
46 |
} catch (err) {
|
47 |
console.error("wordsFrequencyAnalyzers::err on webserver request/response:", err, "#")
|
48 |
console.log(`wordsFrequencyAnalyzers::wordsFrequencyURL: ${typeof wordsFrequencyURL}:`, wordsFrequencyURL, "#")
|
@@ -64,7 +65,7 @@ const wordsFrequencyAnalyzers = {
|
|
64 |
let freq = bodyResponseJson["wordsStemsDict"]
|
65 |
let nTotalRows = bodyResponseJson["nTotalRows"]
|
66 |
console.log(`getWordsFreq::nTotalRows: '${nTotalRows}', populateWordsFrequencyTables...`)
|
67 |
-
populateWordsFrequencyTables(freq, nTotalRows)
|
68 |
// temp until we have the new UI
|
69 |
let hiddenOutputSpan = document.getElementById("id-hidden-editor")
|
70 |
hiddenOutputSpan.textContent = JSON.stringify(freq, null, 2)
|
@@ -362,7 +363,6 @@ function getFormDataByKey(formId, key) {
|
|
362 |
*
|
363 |
* @function previewFile
|
364 |
* @description Displays the contents of a selected text file within an element with id 'editor'.
|
365 |
-
* @param {none}
|
366 |
*/
|
367 |
function previewFile() {
|
368 |
const editor = document.getElementById(editorFieldLabel);
|
@@ -437,8 +437,8 @@ function setCaret(line, offsetColumn, nRowChild, nRowParent) {
|
|
437 |
editorElement.focus();
|
438 |
|
439 |
const offsetsEditor = getOffsetsWithElement(editorElement)
|
440 |
-
const yBase =
|
441 |
-
const y =
|
442 |
const yClientOffset = y - yBase
|
443 |
|
444 |
scrollToGivenPoint(editorElement, yClientOffset)
|
@@ -596,7 +596,7 @@ function arrayFilterNestedValue(array, nestedValue) {
|
|
596 |
/**
|
597 |
* Updates the words frequency tables with new data.
|
598 |
*
|
599 |
-
* Called whenever a change in form input fields or the uploaded text file affects the
|
600 |
* Sorts and filters the word groups based on user preferences, and updates the HTML elements containing these tables.
|
601 |
*
|
602 |
* @function updateWordsFrequencyTables
|
@@ -634,17 +634,19 @@ function updateWordsFrequencyTables() {
|
|
634 |
}
|
635 |
|
636 |
/**
|
637 |
-
* Populate the
|
638 |
*
|
639 |
* @param {Object|string} wordsFrequencyObj - The object or JSON string containing word frequencies.
|
640 |
* @param {number} nTotalRows - The total number of lines/rows to display for each word group.
|
|
|
641 |
*/
|
642 |
-
function populateWordsFrequencyTables(wordsFrequencyObj, nTotalRows) {
|
643 |
wfo["words_frequency"] = wordsFrequencyObj
|
644 |
if (typeof wordsFrequencyObj === "string") {
|
645 |
wfo["words_frequency"] = JSON.parse(wordsFrequencyObj)
|
646 |
}
|
647 |
wfo["nTotalRows"] = nTotalRows
|
|
|
648 |
updateWordsFrequencyTables()
|
649 |
}
|
650 |
|
@@ -665,18 +667,11 @@ function insertCurrentTable(i, iReduced, currentTableOfWords) {
|
|
665 |
currentCaption.setAttribute("aria-label", `id-table-${i}-caption`)
|
666 |
currentCaption.innerText = `${iReduced["word_prefix"]}: ${iReduced["count"]} repetitions`
|
667 |
|
668 |
-
let currentTHead = document.createElement("thead")
|
669 |
-
let currentTHeadRow = currentTHead.insertRow()
|
670 |
-
currentTHeadRow.insertCell().textContent = 'word'
|
671 |
-
currentTHeadRow.insertCell().textContent = 'row nth'
|
672 |
-
currentTHeadRow.insertCell().textContent = 'offsets'
|
673 |
-
|
674 |
let currentTBody = document.createElement("tbody")
|
675 |
let offsetsArray = iReduced.offsets_array
|
676 |
for (let ii = 0; ii < offsetsArray.length; ii++) {
|
677 |
insertCellIntoTRow(currentTBody, i, ii, offsetsArray[ii])
|
678 |
}
|
679 |
-
currentTableWordsFreq.appendChild(currentTHead)
|
680 |
currentTableWordsFreq.appendChild(currentTBody)
|
681 |
currentTableOfWords.appendChild(currentTableWordsFreq)
|
682 |
}
|
@@ -713,13 +708,15 @@ function insertListOfWords(i, iReduced, wordListElement, currentTableOfWords) {
|
|
713 |
* @param {Object} nthOffset - An object containing information about a single offset word, including its row number and word text.
|
714 |
*/
|
715 |
function insertCellIntoTRow(currentTBody, i, ii, nthOffset) {
|
|
|
716 |
let nthRowBody = currentTBody.insertRow()
|
717 |
nthRowBody.setAttribute("id", `id-table-${i}-row-${ii}-nth`)
|
718 |
nthRowBody.setAttribute("aria-label", `id-table-${i}-row-${ii}-nth`)
|
|
|
719 |
let currentCell = nthRowBody.insertCell()
|
720 |
let currentUrl = document.createElement("a")
|
721 |
currentUrl.addEventListener("click", function() {
|
722 |
-
let nRow =
|
723 |
let nRowChild = nthOffset["n_row_child"]
|
724 |
let nRowParent = nthOffset["n_row_parent"]
|
725 |
let offsetWord = nthOffset["offsets"]
|
@@ -728,16 +725,91 @@ function insertCellIntoTRow(currentTBody, i, ii, nthOffset) {
|
|
728 |
currentUrl.className = underlinedClickedTable
|
729 |
})
|
730 |
currentUrl.className = underlinedPrimary
|
731 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
732 |
currentCell.appendChild(currentUrl)
|
733 |
-
|
734 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
735 |
}
|
736 |
|
737 |
/**
|
738 |
-
* Updates the
|
739 |
* If the event target has a value (i.e., it's an input field) and the event key is "Enter",
|
740 |
-
* call the updateWordsFrequencyTables function to update the
|
741 |
*
|
742 |
* @returns {void}
|
743 |
*/
|
|
|
1 |
const wordsFrequencyTableTitleText = "Words Frequency Stats"
|
2 |
let wfo = {
|
3 |
"words_frequency": {},
|
4 |
+
"nTotalRows": null,
|
5 |
+
"rowArray": []
|
6 |
}
|
7 |
const editorFieldLabel = "editor"
|
8 |
const remoteWebServer = "http://localhost:7860"
|
|
|
43 |
let freq = bodyResponseJson["words_frequency"]
|
44 |
let nTotalRows = bodyResponseJson["n_total_rows"]
|
45 |
console.log(`wordsFrequencyAnalyzers::nTotalRows: '${nTotalRows}'`)
|
46 |
+
populateWordsFrequencyTables(freq, nTotalRows, arrayOfValidTextChildWithNrow)
|
47 |
} catch (err) {
|
48 |
console.error("wordsFrequencyAnalyzers::err on webserver request/response:", err, "#")
|
49 |
console.log(`wordsFrequencyAnalyzers::wordsFrequencyURL: ${typeof wordsFrequencyURL}:`, wordsFrequencyURL, "#")
|
|
|
65 |
let freq = bodyResponseJson["wordsStemsDict"]
|
66 |
let nTotalRows = bodyResponseJson["nTotalRows"]
|
67 |
console.log(`getWordsFreq::nTotalRows: '${nTotalRows}', populateWordsFrequencyTables...`)
|
68 |
+
populateWordsFrequencyTables(freq, nTotalRows, inputText)
|
69 |
// temp until we have the new UI
|
70 |
let hiddenOutputSpan = document.getElementById("id-hidden-editor")
|
71 |
hiddenOutputSpan.textContent = JSON.stringify(freq, null, 2)
|
|
|
363 |
*
|
364 |
* @function previewFile
|
365 |
* @description Displays the contents of a selected text file within an element with id 'editor'.
|
|
|
366 |
*/
|
367 |
function previewFile() {
|
368 |
const editor = document.getElementById(editorFieldLabel);
|
|
|
437 |
editorElement.focus();
|
438 |
|
439 |
const offsetsEditor = getOffsetsWithElement(editorElement)
|
440 |
+
const yBase = offsetsEditor.top
|
441 |
+
const {y} = getBoundingClientRect(rng)
|
442 |
const yClientOffset = y - yBase
|
443 |
|
444 |
scrollToGivenPoint(editorElement, yClientOffset)
|
|
|
596 |
/**
|
597 |
* Updates the words frequency tables with new data.
|
598 |
*
|
599 |
+
* Called whenever a change in form input fields or the uploaded text file affects the word frequency table's content.
|
600 |
* Sorts and filters the word groups based on user preferences, and updates the HTML elements containing these tables.
|
601 |
*
|
602 |
* @function updateWordsFrequencyTables
|
|
|
634 |
}
|
635 |
|
636 |
/**
|
637 |
+
* Populate the word frequency tables in the UI with data from the provided object or JSON string.
|
638 |
*
|
639 |
* @param {Object|string} wordsFrequencyObj - The object or JSON string containing word frequencies.
|
640 |
* @param {number} nTotalRows - The total number of lines/rows to display for each word group.
|
641 |
+
* @param rowArray - An array of objects representing the rows of text, each containing the text and its corresponding index.
|
642 |
*/
|
643 |
+
function populateWordsFrequencyTables(wordsFrequencyObj, nTotalRows, rowArray) {
|
644 |
wfo["words_frequency"] = wordsFrequencyObj
|
645 |
if (typeof wordsFrequencyObj === "string") {
|
646 |
wfo["words_frequency"] = JSON.parse(wordsFrequencyObj)
|
647 |
}
|
648 |
wfo["nTotalRows"] = nTotalRows
|
649 |
+
wfo["rowArray"] = Object.values(rowArray)
|
650 |
updateWordsFrequencyTables()
|
651 |
}
|
652 |
|
|
|
667 |
currentCaption.setAttribute("aria-label", `id-table-${i}-caption`)
|
668 |
currentCaption.innerText = `${iReduced["word_prefix"]}: ${iReduced["count"]} repetitions`
|
669 |
|
|
|
|
|
|
|
|
|
|
|
|
|
670 |
let currentTBody = document.createElement("tbody")
|
671 |
let offsetsArray = iReduced.offsets_array
|
672 |
for (let ii = 0; ii < offsetsArray.length; ii++) {
|
673 |
insertCellIntoTRow(currentTBody, i, ii, offsetsArray[ii])
|
674 |
}
|
|
|
675 |
currentTableWordsFreq.appendChild(currentTBody)
|
676 |
currentTableOfWords.appendChild(currentTableWordsFreq)
|
677 |
}
|
|
|
708 |
* @param {Object} nthOffset - An object containing information about a single offset word, including its row number and word text.
|
709 |
*/
|
710 |
function insertCellIntoTRow(currentTBody, i, ii, nthOffset) {
|
711 |
+
let rowArray = wfo["rowArray"]
|
712 |
let nthRowBody = currentTBody.insertRow()
|
713 |
nthRowBody.setAttribute("id", `id-table-${i}-row-${ii}-nth`)
|
714 |
nthRowBody.setAttribute("aria-label", `id-table-${i}-row-${ii}-nth`)
|
715 |
+
const nthRowIdx = nthOffset["n_row"]
|
716 |
let currentCell = nthRowBody.insertCell()
|
717 |
let currentUrl = document.createElement("a")
|
718 |
currentUrl.addEventListener("click", function() {
|
719 |
+
let nRow = nthRowIdx
|
720 |
let nRowChild = nthOffset["n_row_child"]
|
721 |
let nRowParent = nthOffset["n_row_parent"]
|
722 |
let offsetWord = nthOffset["offsets"]
|
|
|
725 |
currentUrl.className = underlinedClickedTable
|
726 |
})
|
727 |
currentUrl.className = underlinedPrimary
|
728 |
+
const wfoContainerWidth = getStylePropertyById("id-col2-words-frequency", "width", "int")
|
729 |
+
const listOfWordsWidth = getStylePropertyById("id-list-of-words", "width", "int")
|
730 |
+
const sentencesContainerWidth = wfoContainerWidth - listOfWordsWidth
|
731 |
+
const nCharsMore = Math.floor(sentencesContainerWidth / 20)
|
732 |
+
console.log(`insertCellIntoTRow::sentencesContainerWidth: ${sentencesContainerWidth}px, nCharsMore: ${nCharsMore}.`)
|
733 |
+
const {substring0, substringWord, substring2} = getSubstringForTextWithGivenOffset(rowArray, nthRowIdx, nthOffset, nCharsMore)
|
734 |
+
|
735 |
+
const span0 = document.createElement("span").innerText = substring0
|
736 |
+
const spanWord = document.createElement("span")
|
737 |
+
spanWord.setAttribute("class", "font-weight-bold")
|
738 |
+
spanWord.innerText = substringWord
|
739 |
+
const span2 = document.createElement("span").innerText = substring2
|
740 |
+
currentUrl.append(span0)
|
741 |
+
currentUrl.append(spanWord)
|
742 |
+
currentUrl.append(span2)
|
743 |
currentCell.appendChild(currentUrl)
|
744 |
+
}
|
745 |
+
|
746 |
+
function getSubstringForTextWithGivenOffset(rowArray, nthRowIdx, nthOffset, nCharsMore = 30) {
|
747 |
+
try {
|
748 |
+
const currentRowArr = rowArray.filter(item => {
|
749 |
+
if (item.idxRowChild !== null) {
|
750 |
+
return item.idxRow === nthRowIdx && item.idxRowChild === nthOffset["n_row_child"] && item.idxRowParent === nthOffset["n_row_parent"]
|
751 |
+
}
|
752 |
+
return item.idxRow === nthRowIdx
|
753 |
+
})
|
754 |
+
const currentRow = currentRowArr[0]
|
755 |
+
const text = currentRow.text
|
756 |
+
let offset = nthOffset["offsets"]
|
757 |
+
let start = offset[0]
|
758 |
+
let end = offset[1]
|
759 |
+
let currentWord = nthOffset["word"]
|
760 |
+
let startOffset = Math.max(0, start - nCharsMore)
|
761 |
+
let endOffset = Math.min(text.length, end + nCharsMore)
|
762 |
+
let substringWord = text.substring(start, end)
|
763 |
+
|
764 |
+
// Prune incomplete word at the start
|
765 |
+
let substring0 = text.substring(startOffset, start)
|
766 |
+
substring0 = substring0.replace(/^\S*\s?/, '') // remove partial word at the start
|
767 |
+
|
768 |
+
// Prune incomplete word at the end
|
769 |
+
let substring2 = text.substring(end, endOffset)
|
770 |
+
substring2 = substring2.replace(/\s?\S*$/, '') // remove partial word at the end
|
771 |
+
|
772 |
+
// Rebuild substring for validation
|
773 |
+
let substring = substring0 + substringWord + substring2
|
774 |
+
|
775 |
+
if (substringWord !== currentWord || substring !== substring0 + substringWord + substring2) {
|
776 |
+
console.assert(substringWord === currentWord,
|
777 |
+
`text.substring(${start}, ${end}) !== currentWord: '${substringWord}', '${currentWord}'.`
|
778 |
+
)
|
779 |
+
console.assert(substring === substring0 + substringWord + substring2,
|
780 |
+
`## text.substring(${startOffset}, ${endOffset}) !== text.substring(${startOffset}, ${start}) + currentWord + text.substring(${end}, ${endOffset}).`
|
781 |
+
)
|
782 |
+
throw Error(`text.substring(${start}, ${end}): (${substringWord}) !== currentWord (${currentWord}).`)
|
783 |
+
}
|
784 |
+
return {substring0, substringWord, substring2};
|
785 |
+
} catch (e) {
|
786 |
+
console.error(`getSubstringForTextWithGivenOffset::error:`, e, ` #`)
|
787 |
+
throw e
|
788 |
+
}
|
789 |
+
}
|
790 |
+
|
791 |
+
function getStylePropertyById(id, property, parsing="") {
|
792 |
+
const element = document.getElementById(id)
|
793 |
+
return getStylePropertyWithElement(element, property, parsing)
|
794 |
+
}
|
795 |
+
|
796 |
+
function getStylePropertyWithElement(element, property, parsing="") {
|
797 |
+
const howToParse = {
|
798 |
+
"int": parseInt,
|
799 |
+
"float": parseFloat
|
800 |
+
}
|
801 |
+
const elementStyle = window.getComputedStyle(element)
|
802 |
+
let value = elementStyle.getPropertyValue(property)
|
803 |
+
if (howToParse[parsing] !== undefined) {
|
804 |
+
value = howToParse[parsing](value, 10)
|
805 |
+
}
|
806 |
+
return value
|
807 |
}
|
808 |
|
809 |
/**
|
810 |
+
* Updates the word frequency tables with new data if enter key is pressed.
|
811 |
* If the event target has a value (i.e., it's an input field) and the event key is "Enter",
|
812 |
+
* call the updateWordsFrequencyTables function to update the word frequency tables.
|
813 |
*
|
814 |
* @returns {void}
|
815 |
*/
|