]> BookStack Code Mirror - bookstack/blobdiff - resources/js/components/shelf-sort.js
Opensearch: Fixed XML declaration when php short tags enabled
[bookstack] / resources / js / components / shelf-sort.js
index 07526716a932da86ca34bbec46f8e8cbfa4bf7b3..b56b01980a147cc17f9cda63bdff62b2ccdf47e4 100644 (file)
@@ -1,6 +1,8 @@
-import Sortable from "sortablejs";
+import Sortable from 'sortablejs';
+import {Component} from './component';
+import {buildListActions, sortActionClickListener} from '../services/dual-lists.ts';
 
-class ShelfSort {
+export class ShelfSort extends Component {
 
     setup() {
         this.elem = this.$el;
@@ -8,6 +10,9 @@ class ShelfSort {
         this.shelfBookList = this.$refs.shelfBookList;
         this.allBookList = this.$refs.allBookList;
         this.bookSearchInput = this.$refs.bookSearch;
+        this.sortButtonContainer = this.$refs.sortButtonContainer;
+
+        this.lastSort = null;
 
         this.initSortable();
         this.setupListeners();
@@ -15,10 +20,11 @@ class ShelfSort {
 
     initSortable() {
         const scrollBoxes = this.elem.querySelectorAll('.scroll-box');
-        for (let scrollBox of scrollBoxes) {
+        for (const scrollBox of scrollBoxes) {
             new Sortable(scrollBox, {
                 group: 'shelf-books',
                 ghostClass: 'primary-background-light',
+                handle: '.handle',
                 animation: 150,
                 onSort: this.onChange.bind(this),
             });
@@ -26,28 +32,30 @@ class ShelfSort {
     }
 
     setupListeners() {
-        this.elem.addEventListener('click', event => {
-            const sortItem = event.target.closest('.scroll-box-item');
-            if (sortItem) {
-                event.preventDefault();
-                this.sortItemClick(sortItem);
-            }
-        });
+        const listActions = buildListActions(this.allBookList, this.shelfBookList);
+        const sortActionListener = sortActionClickListener(listActions, this.onChange.bind(this));
+        this.elem.addEventListener('click', sortActionListener);
 
-        this.bookSearchInput.addEventListener('input', event => {
+        this.bookSearchInput.addEventListener('input', () => {
             this.filterBooksByName(this.bookSearchInput.value);
         });
+
+        this.sortButtonContainer.addEventListener('click', event => {
+            const button = event.target.closest('button[data-sort]');
+            if (button) {
+                this.sortShelfBooks(button.dataset.sort);
+            }
+        });
     }
 
     /**
      * @param {String} filterVal
      */
     filterBooksByName(filterVal) {
-
         // Set height on first search, if not already set, to prevent the distraction
         // of the list height jumping around
         if (!this.allBookList.style.height) {
-            this.allBookList.style.height = this.allBookList.getBoundingClientRect().height + 'px';
+            this.allBookList.style.height = `${this.allBookList.getBoundingClientRect().height}px`;
         }
 
         const books = this.allBookList.children;
@@ -59,24 +67,32 @@ class ShelfSort {
         }
     }
 
-    /**
-     * Called when a sort item is clicked.
-     * @param {Element} sortItem
-     */
-    sortItemClick(sortItem) {
-        const lists = this.elem.querySelectorAll('.scroll-box');
-        const newList = Array.from(lists).filter(list => sortItem.parentElement !== list);
-        if (newList.length > 0) {
-            newList[0].appendChild(sortItem);
-        }
-        this.onChange();
-    }
-
     onChange() {
         const shelfBookElems = Array.from(this.shelfBookList.querySelectorAll('[data-id]'));
         this.input.value = shelfBookElems.map(elem => elem.getAttribute('data-id')).join(',');
     }
 
-}
+    sortShelfBooks(sortProperty) {
+        const books = Array.from(this.shelfBookList.children);
+        const reverse = sortProperty === this.lastSort;
+
+        books.sort((bookA, bookB) => {
+            const aProp = bookA.dataset[sortProperty].toLowerCase();
+            const bProp = bookB.dataset[sortProperty].toLowerCase();
+
+            if (reverse) {
+                return bProp.localeCompare(aProp);
+            }
+
+            return aProp.localeCompare(bProp);
+        });
 
-export default ShelfSort;
\ No newline at end of file
+        for (const book of books) {
+            this.shelfBookList.append(book);
+        }
+
+        this.lastSort = (this.lastSort === sortProperty) ? null : sortProperty;
+        this.onChange();
+    }
+
+}