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