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 });