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

commit 8e9344e37d0bcf97f553b22e7b5a4a0727b64f60
parent 7cd1b6f4d15c5cb8756547e76efe1a6ce5bc4a48
Author: ashermorgan <59518073+ashermorgan@users.noreply.github.com>
Date:   Fri,  2 Apr 2021 12:21:29 -0700

Implement reference table sorting

Diffstat:
Mcss/reference.css | 4++++
Aimages/chevron-down.svg | 2++
Aimages/chevron-up.svg | 2++
Mjs/reference.js | 69++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mtests/test.reference.js | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 184 insertions(+), 1 deletion(-)

diff --git a/css/reference.css b/css/reference.css @@ -52,6 +52,10 @@ position: -webkit-sticky; top: 0; } +.referenceTable th div { + display: flex; + align-items: center; +} .referenceTable td { border: 1px solid var(--border-color); cursor: pointer; diff --git a/images/chevron-down.svg b/images/chevron-down.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-down"><polyline points="6 9 12 15 18 9"></polyline></svg> +\ No newline at end of file diff --git a/images/chevron-up.svg b/images/chevron-up.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-up"><polyline points="18 15 12 9 6 15"></polyline></svg> +\ No newline at end of file diff --git a/js/reference.js b/js/reference.js @@ -11,6 +11,15 @@ const referenceTables = Vue.component("referenceTables", { category: "Choose a category", query: "", conjugationColors: true, + sortIndex: 0, + sortAccending: true, + } + }, + watch: { + category: function() { + // Reset sortIndex and sortAccending + this.sortIndex = 0; + this.sortAccending = true; } }, computed: { @@ -70,6 +79,54 @@ const referenceTables = Vue.component("referenceTables", { }, /** + * Sort the table by values in a column + * @param {Number} index The index of the column to sort by + * @param {Boolean} accending Whether to sort accending or descending + */ + sortColumn: function(index, accending) { + // Get sort direction + let direction; + if (accending !== undefined) { + direction = accending; + } + else if (this.sortIndex === index) { + direction = !this.sortAccending; + } + else { + direction = true; + } + + // Remove headers + let headers = this.data[this.category][0]; + this.data[this.category] = this.data[this.category].slice(1); + + // Sort data + if (this.sortIndex === index && this.sortAccending === direction) { + // Data is sorted by correct column AND in correct direction + } + else if (this.sortIndex === index && this.sortAccending !== direction) { + // Data is sorted by correct column but in wrong direction + this.data[this.category].reverse(); + } + else { + // Data is sorted by incorrect column AND in incorrect direction + this.data[this.category].sort((a, b) => { + if (a[index] === b[index]) return 0; + else if (a[index] < b[index]) return -1; + else return 1; + }); + if (!direction) this.data[this.category].reverse(); + } + + // Reinsert headers + this.data[this.category].unshift(headers); + + // Set sortStatus + this.sortIndex = index; + this.sortAccending = direction; + }, + + /** * Set the table height. */ setTableHeight: function() { @@ -158,7 +215,17 @@ const referenceTables = Vue.component("referenceTables", { <div class="referenceTable" ref="referenceTable"> <table> <tr v-for="(row, rowIndex) in data[category]" v-show="rowIndex === 0 || row.join(',').toLowerCase().includes(query.toLowerCase())"> - <th v-if="rowIndex === 0" v-for="column in row">{{ column }}</th> + <th v-if="rowIndex === 0" v-for="(column, columnIndex) in row" @click="sortColumn(columnIndex)"> + <div> + <span>{{ column }}</span> + <button class="icon"> + <img v-if="sortIndex === columnIndex && sortAccending" src="images/chevron-up.svg"> + </button> + <button class="icon"> + <img v-if="sortIndex === columnIndex && !sortAccending" src="images/chevron-down.svg"> + </button> + </div> + </th> <td v-if="rowIndex !== 0" v-for="(column, columnIndex) in row" @click="Read(column, data[category][0][columnIndex])" :lang="getLang(data[category][0][columnIndex])" :class="(conjugationColors && category === 'verbs') ? conjugationColorClasses[rowIndex][columnIndex] : 'normal'">{{ column }}</td> </tr> diff --git a/tests/test.reference.js b/tests/test.reference.js @@ -17,6 +17,30 @@ describe("ReferenceTables", function() { it("ConjugationColors should be true", function() { expect(ReferenceTables.conjugationColors).to.be.true; }); + + it("SortIndex should be 0", function() { + expect(ReferenceTables.sortIndex).to.equal(0); + }); + + it("SortAccending should be true", function() { + expect(ReferenceTables.sortAccending).to.be.true; + }); + }); + + describe("Category watch", function() { + it("Should reset sortIndex and sortAccending", async function() { + // Set sortIndex and sortAccending + ReferenceTables.sortIndex = 1; + ReferenceTables.sortAccending = false; + + // Set category + ReferenceTables.category = "new category"; + await ReferenceTables.$nextTick(); + + // Assert sortIndex and sortAccending are reset + expect(ReferenceTables.sortIndex).to.equal(0); + expect(ReferenceTables.sortAccending).to.be.true; + }); }); describe("ConjugationColorClasses property", function() { @@ -84,4 +108,88 @@ describe("ReferenceTables", function() { expect(ReferenceTables.tableData).to.deep.equal({...{"Choose a category":[]}, ...data}); }); }); + + describe("SortColumn method", function() { + it("Should correctly sort table", function() { + // Set table data and category + ReferenceTables.data = {"category1":[ + ["English", "Spanish"], + ["Red", "Rojo"], + ["Green", "Verde"], + ["Blue", "Azul"], + ]}; + ReferenceTables.category = "category1"; + + // Sort table + ReferenceTables.sortColumn(1, false); + + // Assert table data is correct + expect(ReferenceTables.data).to.deep.equal({"category1":[ + ["English", "Spanish"], + ["Green", "Verde"], + ["Red", "Rojo"], + ["Blue", "Azul"], + ]}); + + // Assert sortIndex and sortAccending are correct + expect(ReferenceTables.sortIndex).to.equal(1); + expect(ReferenceTables.sortAccending).to.be.false; + }); + + it("Should correctly choose sort direction if column is already sorted", function() { + // Set variables + ReferenceTables.data = {"category1":[ + ["English", "Spanish"], + ["Blue", "Azul"], + ["Red", "Rojo"], + ["Green", "Verde"], + ]}; + ReferenceTables.category = "category1"; + ReferenceTables.sortIndex = 1; + ReferenceTables.sortAccending = true; + + // Sort table + ReferenceTables.sortColumn(1); + + // Assert table data is correct + expect(ReferenceTables.data).to.deep.equal({"category1":[ + ["English", "Spanish"], + ["Green", "Verde"], + ["Red", "Rojo"], + ["Blue", "Azul"], + ]}); + + // Assert sortIndex and sortAccending are correct + expect(ReferenceTables.sortIndex).to.equal(1); + expect(ReferenceTables.sortAccending).to.be.false; + }); + + it("Should correctly choose sort direction if column is not already sorted", function() { + // Set variables + ReferenceTables.data = {"category1":[ + ["English", "Spanish"], + ["Blue", "Azul"], + ["Green", "Verde"], + ["Red", "Rojo"], + ]}; + ReferenceTables.category = "category1"; + ReferenceTables.sortIndex = 0; + ReferenceTables.sortAccending = true; + + // Sort table + ReferenceTables.sortColumn(1); + + // Assert table data is correct + expect(ReferenceTables.data.category1).to.deep.equal([ + ["English", "Spanish"], + ["Blue", "Azul"], + ["Red", "Rojo"], + ["Green", "Verde"], + ]); + + // Assert sortIndex and sortAccending are correct + expect(ReferenceTables.sortIndex).to.equal(1); + expect(ReferenceTables.sortAccending).to.be.true; + }); + }); });