Skip to content

Commit

Permalink
Added shelf book item sort action functionality
Browse files Browse the repository at this point in the history
Adds JS logic, and dropdown action list, for quick-sorting the book
shelf list in addition to handling the book item action buttons.
  • Loading branch information
ssddanbrown committed Feb 17, 2023
1 parent 71a09bc commit 9c26ccf
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 16 deletions.
81 changes: 69 additions & 12 deletions resources/js/components/shelf-sort.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,30 @@
import Sortable from "sortablejs";
import {Component} from "./component";

/**
* @type {Object<string, function(HTMLElement, HTMLElement, HTMLElement)>}
*/
const itemActions = {
move_up(item, shelfBooksList, allBooksList) {
const list = item.parentNode;
const index = Array.from(list.children).indexOf(item);
const newIndex = Math.max(index - 1, 0);
list.insertBefore(item, list.children[newIndex] || null);
},
move_down(item, shelfBooksList, allBooksList) {
const list = item.parentNode;
const index = Array.from(list.children).indexOf(item);
const newIndex = Math.min(index + 2, list.children.length);
list.insertBefore(item, list.children[newIndex] || null);
},
remove(item, shelfBooksList, allBooksList) {
allBooksList.appendChild(item);
},
add(item, shelfBooksList, allBooksList) {
shelfBooksList.appendChild(item);
},
};

export class ShelfSort extends Component {

setup() {
Expand All @@ -9,6 +33,9 @@ export class ShelfSort extends Component {
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();
Expand All @@ -29,16 +56,22 @@ export class ShelfSort extends Component {

setupListeners() {
this.elem.addEventListener('click', event => {
const sortItem = event.target.closest('.scroll-box-item');
if (sortItem) {
event.preventDefault();
this.sortItemClick(sortItem);
const sortItemAction = event.target.closest('.scroll-box-item button[data-action]');
if (sortItemAction) {
this.sortItemActionClick(sortItemAction);
}
});

this.bookSearchInput.addEventListener('input', event => {
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);
}
});
}

/**
Expand All @@ -62,15 +95,16 @@ export class ShelfSort extends Component {
}

/**
* Called when a sort item is clicked.
* @param {Element} sortItem
* Called when a sort item action button is clicked.
* @param {HTMLElement} sortItemAction
*/
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);
}
sortItemActionClick(sortItemAction) {
const sortItem = sortItemAction.closest('.scroll-box-item');
const action = sortItemAction.dataset.action;

const actionFunction = itemActions[action];
actionFunction(sortItem, this.shelfBookList, this.allBookList);

this.onChange();
}

Expand All @@ -79,4 +113,27 @@ export class ShelfSort extends Component {
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 aProp < bProp ? (aProp === bProp ? 0 : 1) : -1;
}

return aProp < bProp ? (aProp === bProp ? 0 : -1) : 1;
});

for (const book of books) {
this.shelfBookList.append(book);
}

this.lastSort = (this.lastSort === sortProperty) ? null : sortProperty;
this.onChange();
}

}
8 changes: 5 additions & 3 deletions resources/sass/_components.scss
Original file line number Diff line number Diff line change
Expand Up @@ -1057,7 +1057,7 @@ $btt-size: 40px;
list-style: none;
padding: 0;
margin: 0;
max-height: 250px;
max-height: 280px;
overflow-y: scroll;
border: 1px solid;
@include lightDark(border-color, #DDD, #000);
Expand Down Expand Up @@ -1104,7 +1104,6 @@ $btt-size: 40px;

input.scroll-box-search, .scroll-box-header-item {
font-size: 0.8rem;
padding: $-xs $-m;
border: 1px solid;
@include lightDark(border-color, #DDD, #000);
@include lightDark(background-color, #FFF, #222);
Expand All @@ -1125,6 +1124,9 @@ input.scroll-box-search, .scroll-box-header-item {
.scroll-box[refs="shelf-sort@shelf-book-list"] [data-action="add"] {
display: none;
}
.scroll-box[refs="shelf-sort@all-book-list"] [data-action="remove"] {
.scroll-box[refs="shelf-sort@all-book-list"] [data-action="remove"],
.scroll-box[refs="shelf-sort@all-book-list"] [data-action="move_up"],
.scroll-box[refs="shelf-sort@all-book-list"] [data-action="move_down"],
{
display: none;
}
19 changes: 18 additions & 1 deletion resources/views/shelves/parts/form.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,24 @@
<label for="books">{{ trans('entities.shelves_books') }}</label>
<input refs="shelf-sort@input" type="hidden" name="books"
value="{{ isset($shelf) ? $shelf->visibleBooks->implode('id', ',') : '' }}">
<div class="scroll-box-header-item">{{ trans('entities.shelves_drag_books') }}</div>
<div class="scroll-box-header-item flex-container-row items-center py-xs">
<span class="px-m py-xs">{{ trans('entities.shelves_drag_books') }}</span>
<div class="dropdown-container ml-auto" component="dropdown">
<button refs="dropdown@toggle"
type="button"
title="{{ trans('common.more') }}"
class="icon-button px-xs py-xxs mx-xs text-bigger"
aria-haspopup="true"
aria-expanded="false">
@icon('more')
</button>
<div refs="dropdown@menu shelf-sort@sort-button-container" class="dropdown-menu" role="menu">
<button type="button" class="text-item" data-sort="name">{{ trans('entities.books_sort_name') }}</button>
<button type="button" class="text-item" data-sort="created">{{ trans('entities.books_sort_created') }}</button>
<button type="button" class="text-item" data-sort="updated">{{ trans('entities.books_sort_updated') }}</button>
</div>
</div>
</div>
<ul refs="shelf-sort@shelf-book-list" class="scroll-box">
@foreach (($shelf->visibleBooks ?? []) as $book)
@include('shelves.parts.shelf-sort-book-item', ['book' => $book])
Expand Down

0 comments on commit 9c26ccf

Please sign in to comment.