spanish-quizzer

An app to quiz you on Spanish vocabulary and verb conjugations
git clone https://git.ashermorgan.net/spanish-quizzer/
Log | Files | Refs | README

filtersPage.js (15277B)


      1 // filter-input component
      2 const filterInput = Vue.component("filterInput", {
      3     props: {
      4         category: {
      5             type: String,
      6             default: "verbs",
      7         },
      8     },
      9 
     10     computed: {
     11         value: function() {
     12             if (this.category === "verbs") {
     13                 return this.verbFilters;
     14             }
     15             else if (this.category === "vocab") {
     16                 return this.vocabFilters;
     17             }
     18         }
     19     },
     20 
     21     data: function() {
     22         return {
     23             verbFilters: [],
     24             vocabFilters: [],
     25         };
     26     },
     27 
     28     watch: {
     29         value: {
     30             handler: function(value) {
     31                 this.$emit("input", value);
     32             },
     33             deep: true,
     34         },
     35     },
     36 
     37     methods: {
     38         /**
     39          * Add a filter to the filters page.
     40          */
     41         AddFilter: function() {
     42             if (this.category === "verbs") {
     43                 this.verbFilters.push(getSettings().defaultFilters.verbs);
     44             }
     45             else if (this.category === "vocab") {
     46                 this.vocabFilters.push(getSettings().defaultFilters.vocab);
     47             }
     48         },
     49 
     50         /**
     51          * Remove a filter from the filters page.
     52          * @param {Number} index - The index of the verb filter.
     53          */
     54         RemoveFilter: function(index) {
     55             if (this.category === "verbs") {
     56                 this.verbFilters.splice(index, 1);
     57             }
     58             else if (this.category === "vocab") {
     59                 this.vocabFilters.splice(index, 1);
     60             }
     61         },
     62 
     63         /**
     64          * Get the regularity filters available for a verb filter.
     65          * @param {Number} index - The index of the verb filter.
     66          * @returns {object} - An object with boolean properties for each regularity filter.
     67          */
     68         getTenseTypes: function(index) {
     69             // Get filter options
     70             let filters = {"All Types":true, "Reflexive":true, "Regular":true, "Nonregular":true, "Stem Changing":true, "Orthographic":true, "Irregular":true}
     71             switch(this.verbFilters[index].tense)
     72             {
     73                 case "All Tenses":
     74                     break;
     75                 case "Present Participles":
     76                     filters["Reflexive"] = false;
     77                     filters["Orthographic"] = false;
     78                     break;
     79                 case "Past Participles":
     80                     filters["Reflexive"] = false;
     81                     filters["Stem Changing"] = false;
     82                     filters["Orthographic"] = false;
     83                     break;
     84                 case "Present Tense":
     85                     filters["Orthographic"] = false;
     86                     break;
     87                 case "Preterite Tense":
     88                     break;
     89                 case "Imperfect Tense":
     90                     filters["Stem Changing"] = false;
     91                     filters["Orthographic"] = false;
     92                     break;
     93                 case "Conditional Tense":
     94                     filters["Stem Changing"] = false;
     95                     filters["Orthographic"] = false;
     96                     break;
     97                 case "Simple Future Tense":
     98                     filters["Stem Changing"] = false;
     99                     filters["Orthographic"] = false;
    100                     break;
    101                 case "Present Subjunctive Tense":
    102                     break;
    103                 case "Imperfect Subjunctive Tense":
    104                     break;
    105             }
    106 
    107             // Reset type if needed
    108             if (!filters[this.verbFilters[index].type]) {
    109                 this.verbFilters[index].type = "All Types";
    110             }
    111 
    112             // Return filters
    113             return filters;
    114         },
    115 
    116         /**
    117          * Get the subject filters available for a verb filter.
    118          * @param {Number} index - The index of the verb filter.
    119          * @returns {object} - An object with boolean properties for each subject filter.
    120          */
    121         getTenseSubjects: function(index) {
    122             // Set default filters
    123             let filters = {"All Subjects":true, "Type":true, "Yo":true, "Tú":true, "Él":true, "Nosotros":true, "Ellos":true}
    124 
    125             if (["Present Participles", "Past Participles"].includes(this.verbFilters[index].tense)) {
    126                 // Override filters
    127                 filters["Yo"] = false;
    128                 filters["Tú"] = false;
    129                 filters["Él"] = false;
    130                 filters["Nosotros"] = false;
    131                 filters["Ellos"] = false;
    132             }
    133 
    134             // Reset subject
    135             if (["Present Participles", "Past Participles"].includes(this.verbFilters[index].tense) && this.verbFilters[index].subject !== "Type") {
    136                 this.verbFilters[index].subject = "All Subjects";
    137             }
    138 
    139             // Return filters
    140             return filters;
    141         },
    142 
    143         /**
    144          * Get the filters available for a vocab category.
    145          * @param {Number} index - The index of the vocab filter.
    146          * @returns {Array} - An array containing available filters.
    147          */
    148         getCategoryFilters: function(index) {
    149             // Get filter options
    150             let filters = {"All Types":true, "Adjectives":true, "Nouns":true, "Verbs":true}
    151             switch(this.vocabFilters[index].category)
    152             {
    153                 case "Verbs":
    154                     filters["Adjectives"] = false;
    155                     filters["Nouns"] = false;
    156                     filters["Verbs"] = false;
    157                     break;
    158 
    159                 case "Adjectives":
    160                     filters["Nouns"] = false;
    161                     filters["Verbs"] = false;
    162                     break;
    163 
    164                 case "Adverbs":
    165                     filters["Adjectives"] = false;
    166                     filters["Nouns"] = false;
    167                     filters["Verbs"] = false;
    168                     break;
    169 
    170                 case "Prepositions":
    171                 case "Transitions":
    172                 case "Questions":
    173                     filters["Adjectives"] = false;
    174                     filters["Nouns"] = false;
    175                     filters["Verbs"] = false;
    176                     break;
    177 
    178                 case "Colors":
    179                     filters["Nouns"] = false;
    180                     filters["Verbs"] = false;
    181                     break;
    182 
    183                 case "Days":
    184                 case "Months":
    185                 case "Numbers":
    186                     filters["Adjectives"] = false;
    187                     filters["Verbs"] = false;
    188                     break;
    189 
    190                 case "Weather":
    191                 case "Professions":
    192                     filters["Adjectives"] = false;
    193                     break;
    194 
    195                 case "Family":
    196                 case "Clothes":
    197                     filters["Verbs"] = false;
    198                     break;
    199 
    200                 case "Nature":
    201                 case "House":
    202                 case "Vacation":
    203                 case "Childhood":
    204                 case "Food":
    205                 case "Health":
    206                     break;
    207             }
    208 
    209             // Reset type if needed
    210             if (!filters[this.vocabFilters[index].type]) {
    211                 this.vocabFilters[index].type = "All Types";
    212             }
    213 
    214             // Return filters
    215             return filters;
    216         }
    217     },
    218 
    219     template: `
    220         <div class="filtersInput" ref="container">
    221             <div class="verbSettings" v-show="category === 'verbs'">
    222                 <h1>
    223                     Verb Filters
    224                     <button title="Add filter" class="icon" @click="AddFilter();"><img src="./images/plus.svg" alt=""></button>
    225                 </h1>
    226 
    227                 <div v-for="(filter, index) in verbFilters" class="filter">
    228                     <select v-model="filter.tense">
    229                         <option>All Tenses</option>
    230                         <optgroup label="Participles">
    231                             <option>Present Participles</option>
    232                             <option>Past Participles</option>
    233                         </optgroup>
    234                         <optgroup label="Indicative Tenses">
    235                             <option>Present Tense</option>
    236                             <option>Preterite Tense</option>
    237                             <option>Imperfect Tense</option>
    238                             <option>Conditional Tense</option>
    239                             <option>Simple Future Tense</option>
    240                         </optgroup>
    241                         <optgroup label="Subjunctive Tenses">
    242                             <option>Present Subjunctive Tense</option>
    243                             <option>Imperfect Subjunctive Tense</option>
    244                         </optgroup>
    245                     </select>
    246                     <select v-model="filter.type">
    247                         <option v-for="(available, type) in getTenseTypes(index)" :disabled="!available">{{ type }}</option>
    248                     </select>
    249                     <select v-model="filter.subject">
    250                         <option v-for="(available, subject) in getTenseSubjects(index)" :disabled="!available">{{ subject }}</option>
    251                     </select>
    252                     <select v-model="filter.direction">
    253                         <option>Eng. → Conj.</option>
    254                         <option>Esp. → Conj.</option>
    255                         <option>Conj. → Eng.</option>
    256                         <option>Conj. → Esp.</option>
    257                     </select>
    258                     <button title="Remove filter" class="icon" @click="RemoveFilter(index);"><img src="./images/trash.svg" alt=""></button>
    259                 </div>
    260             </div>
    261 
    262 
    263             <div class="vocabSettings" v-show="category === 'vocab'">
    264                 <h1>
    265                     Vocabulary Filters
    266                     <button title="Add filter" class="icon" @click="AddFilter();"><img src="./images/plus.svg" alt=""></button>
    267                 </h1>
    268 
    269                 <div v-for="(filter, index) in vocabFilters" class="filter">
    270                     <select class="vocabSetName" v-model="filter.category">
    271                         <option>All Categories</option>
    272                         <optgroup label="Common Words">
    273                             <option>Adjectives</option>
    274                             <option>Adverbs</option>
    275                             <option>Prepositions</option>
    276                             <option>Transitions</option>
    277                             <option>Verbs</option>
    278                         </optgroup>
    279                         <optgroup label="Basic Words">
    280                             <option>Colors</option>
    281                             <option>Days</option>
    282                             <option>Months</option>
    283                             <option>Numbers</option>
    284                             <option>Questions</option>
    285                         </optgroup>
    286                         <optgroup label="Advanced Words">
    287                             <option>Childhood</option>
    288                             <option>Clothes</option>
    289                             <option>Family</option>
    290                             <option>Food</option>
    291                             <option>Health</option>
    292                             <option>House</option>
    293                             <option>Nature</option>
    294                             <option>Professions</option>
    295                             <option>Vacation</option>
    296                             <option>Weather</option>
    297                         </optgroup>
    298                     </select>
    299                     <select v-model="filter.type">
    300                         <option v-for="(available, type) in getCategoryFilters(index)" :disabled="!available">{{ type }}</option>
    301                     </select>
    302                     <select v-model="filter.direction">
    303                         <option>Eng. ↔ Esp.</option>
    304                         <option>Eng. → Esp.</option>
    305                         <option>Esp. → Eng.</option>
    306                     </select>
    307                     <button title="Remove filter" class="icon" @click="RemoveFilter(index);"><img src="./images/trash.svg" alt=""></button>
    308                 </div>
    309             </div>
    310         </div>
    311     `,
    312 });
    313 
    314 
    315 
    316 // filters-page component
    317 const filtersPage = Vue.component("filtersPage", {
    318     props: {
    319         category: {
    320             type: String,
    321             default: "verbs",
    322         }
    323     },
    324 
    325     data: function() {
    326         return {
    327             filters: [],
    328             settings: getSettings(),
    329         };
    330     },
    331 
    332     methods: {
    333         /**
    334          * Start a new quizzer session
    335          */
    336         StartSession: function() {
    337             // Get prompts
    338             let prompts;
    339             if (this.category === "vocab") {
    340                 prompts = Shuffle(ApplyFilters(this.$root.$data.data.vocab, GetVocabFilters(this.filters), this.settings));
    341             }
    342             else if (this.category === "verbs") {
    343                 // Get prompts
    344                 prompts = Shuffle(ApplyFilters(this.$root.$data.data.verbs, GetVerbFilters(this.filters), this.settings));
    345             }
    346 
    347             // Set progress
    348             let promptIndex = 0;
    349 
    350             // Validate prompts
    351             if (prompts.length === 0) {
    352                 alert("You must have at least one filter.");
    353                 return;
    354             }
    355 
    356             // Validate browser for voice input
    357             if (this.settings.inputType !== "Text") {
    358                 if ((window.SpeechRecognition || window.webkitSpeechRecognition || window.mozSpeechRecognition || window.msSpeechRecognition) === undefined) {
    359                     alert("Your browser does not support voice input.");
    360                     return;
    361                 }
    362             }
    363 
    364             // Start quizzer
    365             this.$router.push({name:"quizzer", params:{startingPrompts:prompts, startingIndex:promptIndex, settings:this.settings, referer:this.category}});
    366         },
    367 
    368         /**
    369          * Handle a keyup event (implements some keyboard shortcuts).
    370          * @param {object} e - The event args.
    371          */
    372         keyup: function(e) {
    373             if (this._inactive || e.ctrlKey || e.altKey || e.shiftKey || e.metaKey) return;
    374             if (e.key === ",") this.$router.push({name:"settings", params:{referer:this.$route.name}});
    375             if (e.key === "s") this.StartSession();
    376         }
    377     },
    378 
    379     created: function() {
    380         // Add keyup handler
    381         window.addEventListener("keyup", this.keyup);
    382     },
    383 
    384     activated: function() {
    385         // Add 1 filter by default
    386         if (this.filters.length === 0) this.$refs.filters.AddFilter();
    387     },
    388 
    389     destroyed: function() {
    390         // Remove keyup handler
    391         window.removeEventListener("keyup", this.keyup);
    392     },
    393 
    394     template: `
    395         <div class="filtersPage">
    396             <page-header icon1="arrow-left" label1="Back" @click1="$emit('back');"
    397                 icon2="settings" label2="Settings" @click2="$router.push({name:'settings', params:{referer:$route.name}})"></page-header>
    398             <main>
    399                 <filter-input ref="filters" :category="category" v-model="filters"></filter-input>
    400                 <h1>Quizzer Settings</h1>
    401                 <settings-input v-model="settings"></settings-input>
    402                 <button class="settingsStart" @click="StartSession();">Start</button>
    403             </main>
    404         </div>
    405     `,
    406 });