|
1 | | -import { writeExploreState, addCard, inStudyList, isFlashCardUser, explainChineseSentence, generateChineseSentences, isAiEligible, countWordsWithoutCards, hasCardWithWord, registerCallback, dataTypes } from "./data-layer.js"; |
| 1 | +import { writeExploreState, addCard, inStudyList, isFlashCardUser, explainChineseSentence, generateChineseSentences, isAiEligible, getWordsWithoutCards, hasCardWithWord, registerCallback, dataTypes } from "./data-layer.js"; |
2 | 2 | import { hanziBox, notFoundElement, walkThrough, examplesList, createLoadingDots } from "./dom.js"; |
3 | 3 | import { getActiveGraph, getPartition } from "./options.js"; |
4 | 4 | import { renderCoverageGraph } from "./coverage-graph" |
@@ -544,23 +544,58 @@ let setupExampleElements = function (word, examples, exampleList, defaultSource) |
544 | 544 | // if the user doesn't use HanziGraph for flashcards, render nothing. |
545 | 545 | // otherwise, let them know how many new words are in the sentence to aid the choice of whether to make a flashcard |
546 | 546 | const words = examples[i].zh.filter(x => x in wordSet); |
547 | | - const unknownWordCount = countWordsWithoutCards(words); |
| 547 | + const unknownWords = getWordsWithoutCards(words); |
548 | 548 | const unknownWordTag = document.createElement('span'); |
549 | | - unknownWordTag.innerHTML = getUnknownWordHtml(unknownWordCount); |
| 549 | + unknownWordTag.innerHTML = getUnknownWordHtml(unknownWords); |
550 | 550 | unknownWordTag.classList.add('tag', 'nowrap'); |
551 | 551 | missingWordElements.push({ unknownWordTag, words }); |
552 | 552 | tagContainer.appendChild(unknownWordTag); |
553 | 553 | exampleHolder.appendChild(tagContainer); |
554 | 554 | exampleList.appendChild(exampleHolder); |
555 | 555 | } |
556 | 556 | }; |
557 | | -function getUnknownWordHtml(unknownWordCount) { |
| 557 | +function getSuitabilityClass(unknownWordSet) { |
| 558 | + // TODO: make these rank cutoffs configurable, and set up a priority color coding graph style |
| 559 | + const minFreqRank = 0; |
| 560 | + const maxFreqRank = 10000; |
| 561 | + const totalUnknownWords = unknownWordSet.size; |
| 562 | + let highPriorityWordCount = 0; |
| 563 | + for (const unknownWord of unknownWordSet) { |
| 564 | + // we assume upstream filtering of words being in the wordset before added to unknownWordSet |
| 565 | + const rank = wordSet[unknownWord]; |
| 566 | + // ranks in wordSet start from 1 for ease of rendering (i.e., 1st most common instead of 0th) |
| 567 | + // so check min is exclusive, max is inclusive |
| 568 | + if (rank <= maxFreqRank && rank > minFreqRank) { |
| 569 | + highPriorityWordCount++; |
| 570 | + } |
| 571 | + } |
| 572 | + // a heuristic approach to determining how suitable a sentence is to be made into a flashcard |
| 573 | + // the idea is that one would want no more than 3 unknown words in a sentence at a time |
| 574 | + // and the number of those that are 'high priority' must be nonzero. |
| 575 | + // this should also probably include a minimum percentage for totalUnknownWords / allWords |
| 576 | + // but for now just use minimum counts |
| 577 | + if (totalUnknownWords <= 3 && highPriorityWordCount > 0) { |
| 578 | + // every unknown word is high priority...great flash card |
| 579 | + if (highPriorityWordCount === totalUnknownWords) { |
| 580 | + return 'max'; |
| 581 | + } |
| 582 | + // all but one of the unknown words are high priority |
| 583 | + if (highPriorityWordCount == (totalUnknownWords - 1)) { |
| 584 | + return 'high'; |
| 585 | + } |
| 586 | + // at least one unknown word is high priority |
| 587 | + return 'medium'; |
| 588 | + } |
| 589 | + return 'low'; |
| 590 | +} |
| 591 | +function getUnknownWordHtml(unknownWords) { |
| 592 | + const unknownWordCount = unknownWords.size; |
558 | 593 | if (!isFlashCardUser()) { |
559 | 594 | return ''; |
560 | 595 | } |
561 | 596 | return unknownWordCount === 0 ? |
562 | 597 | `<span class="deemphasized">✅ No unknown words</span>` : |
563 | | - `<span class="deemphasized">No flashcards: <b>${unknownWordCount} word${unknownWordCount !== 1 ? 's' : ''}</b></span>`; |
| 598 | + `<span class="deemphasized">No flashcards: <b class="${`suitability-${getSuitabilityClass(unknownWords)}`}">${unknownWordCount} word${unknownWordCount !== 1 ? 's' : ''}</b></span>`; |
564 | 599 | } |
565 | 600 |
|
566 | 601 | // expects callers to ensure augmentation is available |
@@ -1178,8 +1213,8 @@ let initialize = function () { |
1178 | 1213 | fetchStats(); |
1179 | 1214 | registerCallback(dataTypes.studyList, function () { |
1180 | 1215 | for (const item of missingWordElements) { |
1181 | | - const unknownWordCount = countWordsWithoutCards(item.words); |
1182 | | - item.unknownWordTag.innerHTML = getUnknownWordHtml(unknownWordCount); |
| 1216 | + const unknownWords = getWordsWithoutCards(item.words); |
| 1217 | + item.unknownWordTag.innerHTML = getUnknownWordHtml(unknownWords); |
1183 | 1218 | } |
1184 | 1219 | for (const item of hasCardsElements) { |
1185 | 1220 | item.cardTag.innerHTML = addFlashCardDefinitionTag(item.word); |
|
0 commit comments