accounts: double click "select all" to load and select -all-
Clicking once will select all visible records, and show as indeterminate. Clicking again will load all records, and select them all once done.
This commit is contained in:
@@ -1469,7 +1469,7 @@ sections:
|
|||||||
description: When set, user accounts will be deleted this many days after expiring
|
description: When set, user accounts will be deleted this many days after expiring
|
||||||
(if "Behaviour" is "Disable user"). Set to 0 to disable.
|
(if "Behaviour" is "Disable user"). Set to 0 to disable.
|
||||||
- setting: send_email
|
- setting: send_email
|
||||||
name: Send email
|
name: Send message
|
||||||
type: bool
|
type: bool
|
||||||
value: true
|
value: true
|
||||||
depends_true: messages|enabled
|
depends_true: messages|enabled
|
||||||
|
|||||||
+3
-2
@@ -751,6 +751,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="supra sm">{{ .strings.actions }}</div>
|
<div class="supra sm">{{ .strings.actions }}</div>
|
||||||
<div class="flex flex-row flex-wrap gap-3">
|
<div class="flex flex-row flex-wrap gap-3">
|
||||||
|
<button class="button ~neutral @low center accounts-load-all">{{ .strings.loadAll }}</button>
|
||||||
<span class="button ~neutral @low center " id="accounts-add-user">{{ .quantityStrings.addUser.Singular }}</span>
|
<span class="button ~neutral @low center " id="accounts-add-user">{{ .quantityStrings.addUser.Singular }}</span>
|
||||||
<div id="accounts-announce-dropdown" class="dropdown pb-0i " tabindex="0">
|
<div id="accounts-announce-dropdown" class="dropdown pb-0i " tabindex="0">
|
||||||
<span class="w-full button ~info @low center items-baseline" id="accounts-announce">{{ .strings.announce }}</span>
|
<span class="w-full button ~info @low center items-baseline" id="accounts-announce">{{ .strings.announce }}</span>
|
||||||
@@ -827,7 +828,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex flex-row gap-2 justify-center">
|
<div class="flex flex-row gap-2 justify-center">
|
||||||
<button class="button ~neutral @low" id="accounts-load-more">{{ .strings.loadMore }}</button>
|
<button class="button ~neutral @low" id="accounts-load-more">{{ .strings.loadMore }}</button>
|
||||||
<button class="button ~neutral @low" id="accounts-load-all">{{ .strings.loadAll }}</button>
|
<button class="button ~neutral @low accounts-load-all">{{ .strings.loadAll }}</button>
|
||||||
<button class="button ~info @low center accounts-search-server flex flex-row gap-1" aria-label="{{ .strings.searchAllRecords }}" text="{{ .strings.searchAllRecords }}">
|
<button class="button ~info @low center accounts-search-server flex flex-row gap-1" aria-label="{{ .strings.searchAllRecords }}" text="{{ .strings.searchAllRecords }}">
|
||||||
<i class="ri-search-line"></i>
|
<i class="ri-search-line"></i>
|
||||||
<span>{{ .strings.searchAllRecords }}</span>
|
<span>{{ .strings.searchAllRecords }}</span>
|
||||||
@@ -889,7 +890,7 @@
|
|||||||
<div id="activity-loader"></div>
|
<div id="activity-loader"></div>
|
||||||
<div class="flex flex-row gap-2 justify-center">
|
<div class="flex flex-row gap-2 justify-center">
|
||||||
<button class="button ~neutral @low" id="activity-load-more">{{ .strings.loadMore }}</button>
|
<button class="button ~neutral @low" id="activity-load-more">{{ .strings.loadMore }}</button>
|
||||||
<button class="button ~neutral @low" id="activity-load-all">{{ .strings.loadAll }}</button>
|
<button class="button ~neutral @low activity-load-all">{{ .strings.loadAll }}</button>
|
||||||
<button class="button ~info @low center activity-search-server flex flex-row gap-1" aria-label="{{ .strings.searchAllRecords }}" text="{{ .strings.searchAllRecords }}">
|
<button class="button ~info @low center activity-search-server flex flex-row gap-1" aria-label="{{ .strings.searchAllRecords }}" text="{{ .strings.searchAllRecords }}">
|
||||||
<i class="ri-search-line"></i>
|
<i class="ri-search-line"></i>
|
||||||
<span>{{ .strings.searchAllRecords }}</span>
|
<span>{{ .strings.searchAllRecords }}</span>
|
||||||
|
|||||||
@@ -194,6 +194,8 @@
|
|||||||
"loadedRecords": "{n} Loaded",
|
"loadedRecords": "{n} Loaded",
|
||||||
"shownRecords": "{n} Shown",
|
"shownRecords": "{n} Shown",
|
||||||
"selectedRecords": "{n} Selected",
|
"selectedRecords": "{n} Selected",
|
||||||
|
"allMatchingSelected": "All matching results selected.",
|
||||||
|
"allLoadedSelected": "All loaded matching results selected. Click again to load all.",
|
||||||
"backups": "Backups",
|
"backups": "Backups",
|
||||||
"backupsDescription": "Backups of the database can be made, restored, or downloaded from here.",
|
"backupsDescription": "Backups of the database can be made, restored, or downloaded from here.",
|
||||||
"backupsFormatNote": "Only backup files with the standard name format will be shown here. To use any other, upload the backup manually.",
|
"backupsFormatNote": "Only backup files with the standard name format will be shown here. To use any other, upload the backup manually.",
|
||||||
|
|||||||
+104
-31
@@ -14,6 +14,13 @@ const USER_DEFAULT_SORT_ASCENDING = true;
|
|||||||
|
|
||||||
const dateParser = require("any-date-parser");
|
const dateParser = require("any-date-parser");
|
||||||
|
|
||||||
|
enum SelectAllState {
|
||||||
|
None = 0,
|
||||||
|
Some = 0.1,
|
||||||
|
AllVisible = 0.9,
|
||||||
|
All = 1
|
||||||
|
};
|
||||||
|
|
||||||
interface User {
|
interface User {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
@@ -218,11 +225,16 @@ class user implements User, SearchableItem {
|
|||||||
|
|
||||||
get selected(): boolean { return this._selected; }
|
get selected(): boolean { return this._selected; }
|
||||||
set selected(state: boolean) {
|
set selected(state: boolean) {
|
||||||
|
this.setSelected(state, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
setSelected(state: boolean, dispatchEvent: boolean) {
|
||||||
this._selected = state;
|
this._selected = state;
|
||||||
this._check.checked = state;
|
this._check.checked = state;
|
||||||
state ? document.dispatchEvent(this._checkEvent()) : document.dispatchEvent(this._uncheckEvent());
|
if (dispatchEvent) state ? document.dispatchEvent(this._checkEvent()) : document.dispatchEvent(this._uncheckEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
get name(): string { return this._username.textContent; }
|
get name(): string { return this._username.textContent; }
|
||||||
set name(value: string) { this._username.textContent = value; }
|
set name(value: string) { this._username.textContent = value; }
|
||||||
|
|
||||||
@@ -869,6 +881,7 @@ export class accountsList extends PaginatedList {
|
|||||||
private _applyJellyseerr = document.getElementById("modify-user-jellyseerr") as HTMLInputElement;
|
private _applyJellyseerr = document.getElementById("modify-user-jellyseerr") as HTMLInputElement;
|
||||||
|
|
||||||
private _selectAll = document.getElementById("accounts-select-all") as HTMLInputElement;
|
private _selectAll = document.getElementById("accounts-select-all") as HTMLInputElement;
|
||||||
|
private _selectAllState: SelectAllState = SelectAllState.None;
|
||||||
// private _users: { [id: string]: user };
|
// private _users: { [id: string]: user };
|
||||||
// private _ordering: string[] = [];
|
// private _ordering: string[] = [];
|
||||||
get users(): { [id: string]: user } { return this._search.items as { [id: string]: user }; }
|
get users(): { [id: string]: user } { return this._search.items as { [id: string]: user }; }
|
||||||
@@ -912,8 +925,8 @@ export class accountsList extends PaginatedList {
|
|||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super({
|
||||||
loader: document.getElementById("accounts-loader"),
|
loader: document.getElementById("accounts-loader"),
|
||||||
loadMoreButton: document.getElementById("accounts-load-more") as HTMLButtonElement,
|
loadMoreButtons: Array.from([document.getElementById("accounts-load-more") as HTMLButtonElement]) as Array<HTMLButtonElement>,
|
||||||
loadAllButton: document.getElementById("accounts-load-all") as HTMLButtonElement,
|
loadAllButtons: Array.from(document.getElementsByClassName("accounts-load-all")) as Array<HTMLButtonElement>,
|
||||||
refreshButton: document.getElementById("accounts-refresh") as HTMLButtonElement,
|
refreshButton: document.getElementById("accounts-refresh") as HTMLButtonElement,
|
||||||
filterArea: document.getElementById("accounts-filter-area"),
|
filterArea: document.getElementById("accounts-filter-area"),
|
||||||
searchOptionsHeader: document.getElementById("accounts-search-options-header"),
|
searchOptionsHeader: document.getElementById("accounts-search-options-header"),
|
||||||
@@ -987,21 +1000,23 @@ export class accountsList extends PaginatedList {
|
|||||||
clearSearchButtonSelector: ".accounts-search-clear",
|
clearSearchButtonSelector: ".accounts-search-clear",
|
||||||
serverSearchButtonSelector: ".accounts-search-server",
|
serverSearchButtonSelector: ".accounts-search-server",
|
||||||
onSearchCallback: (_0: boolean, _1: boolean) => {
|
onSearchCallback: (_0: boolean, _1: boolean) => {
|
||||||
this._checkCheckCount();
|
this.processSelectedAccounts();
|
||||||
},
|
},
|
||||||
searchServer: null,
|
searchServer: null,
|
||||||
clearServerSearch: null,
|
clearServerSearch: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.initSearch(searchConfig);
|
this.initSearch(searchConfig);
|
||||||
|
|
||||||
|
// FIXME: Remove!
|
||||||
|
(window as any).accs = this;
|
||||||
|
|
||||||
this._selectAll.checked = false;
|
this._selectAll.checked = false;
|
||||||
this._selectAll.onchange = () => {
|
this._selectAllState = SelectAllState.None;
|
||||||
this.selectAll = this._selectAll.checked;
|
this._selectAll.onchange = () => this.cycleSelectAll();
|
||||||
};
|
|
||||||
document.addEventListener("accounts-reload", () => this.reload());
|
document.addEventListener("accounts-reload", () => this.reload());
|
||||||
document.addEventListener("accountCheckEvent", () => { this._counter.selected++; this._checkCheckCount(); });
|
document.addEventListener("accountCheckEvent", () => { this._counter.selected++; this.processSelectedAccounts(); });
|
||||||
document.addEventListener("accountUncheckEvent", () => { this._counter.selected--; this._checkCheckCount(); });
|
document.addEventListener("accountUncheckEvent", () => { this._counter.selected--; this.processSelectedAccounts(); });
|
||||||
this._addUserButton.onclick = () => {
|
this._addUserButton.onclick = () => {
|
||||||
this._populateAddUserProfiles();
|
this._populateAddUserProfiles();
|
||||||
window.modals.addUser.toggle();
|
window.modals.addUser.toggle();
|
||||||
@@ -1232,25 +1247,79 @@ export class accountsList extends PaginatedList {
|
|||||||
this.loadTemplates();
|
this.loadTemplates();
|
||||||
}
|
}
|
||||||
|
|
||||||
loadMore = (loadAll: boolean = false, callback?: () => void) => {
|
loadMore = (loadAll: boolean = false, callback?: (resp?: paginatedDTO) => void) => {
|
||||||
this._loadMore(
|
this._loadMore(
|
||||||
loadAll,
|
loadAll,
|
||||||
callback
|
callback
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
get selectAll(): boolean { return this._selectAll.checked; }
|
loadAll = (callback?: (resp?: paginatedDTO) => void) => {
|
||||||
set selectAll(state: boolean) {
|
this._loadAll(callback);
|
||||||
let count = 0;
|
};
|
||||||
for (let id in this.users) {
|
|
||||||
if (this._container.contains(this.users[id].asElement())) { // Only select visible elements
|
get selectAll(): SelectAllState { return this._selectAllState; }
|
||||||
this.users[id].selected = state;
|
|
||||||
|
cycleSelectAll = () => {
|
||||||
|
let next: SelectAllState;
|
||||||
|
switch (this.selectAll) {
|
||||||
|
case SelectAllState.None:
|
||||||
|
case SelectAllState.Some:
|
||||||
|
next = SelectAllState.AllVisible;
|
||||||
|
break;
|
||||||
|
case SelectAllState.AllVisible:
|
||||||
|
next = SelectAllState.All;
|
||||||
|
break;
|
||||||
|
case SelectAllState.All:
|
||||||
|
next = SelectAllState.None;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._selectAllState = next;
|
||||||
|
console.debug("New check state:", next);
|
||||||
|
|
||||||
|
if (next == SelectAllState.None) {
|
||||||
|
// Deselect -all- users, rather than just visible ones, to be safe.
|
||||||
|
for (let id in this.users) {
|
||||||
|
this.users[id].setSelected(false, false);
|
||||||
|
}
|
||||||
|
this._selectAll.checked = false;
|
||||||
|
this._selectAll.indeterminate = false;
|
||||||
|
this.processSelectedAccounts();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Decide whether to keep the AllVisible/All distinction and actually use it, or to get rid of it an just make "load all" more visible.
|
||||||
|
const selectAllVisible = () => {
|
||||||
|
let count = 0;
|
||||||
|
for (let id of this._visible) {
|
||||||
|
this.users[id].setSelected(true, false);
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
console.debug("Selected", count);
|
||||||
|
this._selectAll.checked = true;
|
||||||
|
if (this.lastPage) {
|
||||||
|
this._selectAllState = SelectAllState.All;
|
||||||
|
}
|
||||||
|
this._selectAll.indeterminate = this.lastPage ? false : true;
|
||||||
|
this.processSelectedAccounts();
|
||||||
|
}
|
||||||
|
if (next == SelectAllState.AllVisible) {
|
||||||
|
selectAllVisible();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next == SelectAllState.All) {
|
||||||
|
this.loadAll((_: paginatedDTO) => {
|
||||||
|
if (!(this.lastPage)) {
|
||||||
|
// Pretend to live-select elements as they load.
|
||||||
|
this._counter.selected = this._counter.shown;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selectAllVisible();
|
||||||
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
this._selectAll.checked = state;
|
|
||||||
this._selectAll.indeterminate = false;
|
|
||||||
state ? this._counter.selected = count : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
selectAllBetweenIDs = (startID: string, endID: string) => {
|
selectAllBetweenIDs = (startID: string, endID: string) => {
|
||||||
@@ -1270,12 +1339,14 @@ export class accountsList extends PaginatedList {
|
|||||||
// console.log("after appending lengths:", Object.keys(this.users).length, Object.keys(this._search.items).length);
|
// console.log("after appending lengths:", Object.keys(this.users).length, Object.keys(this._search.items).length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _checkCheckCount = () => {
|
private processSelectedAccounts = () => {
|
||||||
|
console.debug("processSelectedAccounts");
|
||||||
const list = this._collectUsers();
|
const list = this._collectUsers();
|
||||||
this._counter.selected = list.length;
|
this._counter.selected = list.length;
|
||||||
if (this._counter.selected == 0) {
|
if (this._counter.selected == 0) {
|
||||||
this._selectAll.indeterminate = false;
|
this._selectAll.indeterminate = false;
|
||||||
this._selectAll.checked = false;
|
this._selectAll.checked = false;
|
||||||
|
this._selectAll.title = "";
|
||||||
this._modifySettings.classList.add("unfocused");
|
this._modifySettings.classList.add("unfocused");
|
||||||
if (window.referralsEnabled) {
|
if (window.referralsEnabled) {
|
||||||
this._enableReferrals.classList.add("unfocused");
|
this._enableReferrals.classList.add("unfocused");
|
||||||
@@ -1288,15 +1359,17 @@ export class accountsList extends PaginatedList {
|
|||||||
this._disableEnable.parentElement.classList.add("unfocused");
|
this._disableEnable.parentElement.classList.add("unfocused");
|
||||||
this._sendPWR.classList.add("unfocused");
|
this._sendPWR.classList.add("unfocused");
|
||||||
} else {
|
} else {
|
||||||
let visibleCount = 0;
|
if (this._counter.selected == this._visible.length) {
|
||||||
for (let id in this.users) {
|
|
||||||
if (this._container.contains(this.users[id].asElement())) {
|
|
||||||
visibleCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this._counter.selected == visibleCount) {
|
|
||||||
this._selectAll.checked = true;
|
this._selectAll.checked = true;
|
||||||
this._selectAll.indeterminate = false;
|
if (this.lastPage) {
|
||||||
|
this._selectAll.indeterminate = false;
|
||||||
|
this._selectAll.title = window.lang.strings("allMatchingSelected");
|
||||||
|
// FIXME: Hover text "all matching records selected."
|
||||||
|
} else {
|
||||||
|
this._selectAll.indeterminate = true;
|
||||||
|
this._selectAll.title = window.lang.strings("allLoadedSelected");
|
||||||
|
// FIXME: Hover text "all loaded matching records selected. Click again to load all."
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this._selectAll.checked = false;
|
this._selectAll.checked = false;
|
||||||
this._selectAll.indeterminate = true;
|
this._selectAll.indeterminate = true;
|
||||||
@@ -1392,8 +1465,8 @@ export class accountsList extends PaginatedList {
|
|||||||
|
|
||||||
private _collectUsers = (): string[] => {
|
private _collectUsers = (): string[] => {
|
||||||
let list: string[] = [];
|
let list: string[] = [];
|
||||||
for (let id in this.users) {
|
for (let id of this._visible) {
|
||||||
if (this._container.contains(this.users[id].asElement()) && this.users[id].selected) { list.push(id); }
|
if (this.users[id].selected) { list.push(id) }
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -492,8 +492,8 @@ export class activityList extends PaginatedList {
|
|||||||
constructor() {
|
constructor() {
|
||||||
super({
|
super({
|
||||||
loader: document.getElementById("activity-loader"),
|
loader: document.getElementById("activity-loader"),
|
||||||
loadMoreButton: document.getElementById("activity-load-more") as HTMLButtonElement,
|
loadMoreButtons: Array.from([document.getElementById("activity-load-more") as HTMLButtonElement]) as Array<HTMLButtonElement>,
|
||||||
loadAllButton: document.getElementById("activity-load-all") as HTMLButtonElement,
|
loadAllButtons: Array.from(document.getElementsByClassName("activity-load-all")) as Array<HTMLButtonElement>,
|
||||||
refreshButton: document.getElementById("activity-refresh") as HTMLButtonElement,
|
refreshButton: document.getElementById("activity-refresh") as HTMLButtonElement,
|
||||||
filterArea: document.getElementById("activity-filter-area"),
|
filterArea: document.getElementById("activity-filter-area"),
|
||||||
searchOptionsHeader: document.getElementById("activity-search-options-header"),
|
searchOptionsHeader: document.getElementById("activity-search-options-header"),
|
||||||
@@ -571,6 +571,10 @@ export class activityList extends PaginatedList {
|
|||||||
callback
|
callback
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
loadAll = (callback?: (resp?: paginatedDTO) => void) => {
|
||||||
|
this._loadAll(callback);
|
||||||
|
};
|
||||||
|
|
||||||
get ascending(): boolean {
|
get ascending(): boolean {
|
||||||
return this._ascending;
|
return this._ascending;
|
||||||
|
|||||||
+31
-20
@@ -78,8 +78,8 @@ export class RecordCounter {
|
|||||||
|
|
||||||
export interface PaginatedListConfig {
|
export interface PaginatedListConfig {
|
||||||
loader: HTMLElement;
|
loader: HTMLElement;
|
||||||
loadMoreButton: HTMLButtonElement;
|
loadMoreButtons: Array<HTMLButtonElement>;
|
||||||
loadAllButton: HTMLButtonElement;
|
loadAllButtons: Array<HTMLButtonElement>;
|
||||||
refreshButton: HTMLButtonElement;
|
refreshButton: HTMLButtonElement;
|
||||||
filterArea: HTMLElement;
|
filterArea: HTMLElement;
|
||||||
searchOptionsHeader: HTMLElement;
|
searchOptionsHeader: HTMLElement;
|
||||||
@@ -130,13 +130,17 @@ export abstract class PaginatedList {
|
|||||||
set lastPage(v: boolean) {
|
set lastPage(v: boolean) {
|
||||||
this._lastPage = v;
|
this._lastPage = v;
|
||||||
if (v) {
|
if (v) {
|
||||||
this._c.loadAllButton.classList.add("unfocused");
|
this._c.loadAllButtons.forEach((v) => v.classList.add("unfocused"));
|
||||||
this._c.loadMoreButton.textContent = window.lang.strings("noMoreResults");
|
this._c.loadMoreButtons.forEach((v) => {
|
||||||
this._c.loadMoreButton.disabled = true;
|
v.textContent = window.lang.strings("noMoreResults");
|
||||||
|
v.disabled = true;
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
this._c.loadMoreButton.textContent = window.lang.strings("loadMore");
|
this._c.loadMoreButtons.forEach((v) => {
|
||||||
this._c.loadMoreButton.disabled = false;
|
v.textContent = window.lang.strings("loadMore");
|
||||||
this._c.loadAllButton.classList.remove("unfocused");
|
v.disabled = false;
|
||||||
|
});
|
||||||
|
this._c.loadAllButtons.forEach((v) => v.classList.remove("unfocused"));
|
||||||
}
|
}
|
||||||
this.autoSetServerSearchButtonsDisabled();
|
this.autoSetServerSearchButtonsDisabled();
|
||||||
}
|
}
|
||||||
@@ -161,11 +165,12 @@ export abstract class PaginatedList {
|
|||||||
this._counter = new RecordCounter(this._c.recordCounter);
|
this._counter = new RecordCounter(this._c.recordCounter);
|
||||||
this._hasLoaded = false;
|
this._hasLoaded = false;
|
||||||
|
|
||||||
this._c.loadMoreButton.onclick = () => this.loadMore(false);
|
this._c.loadMoreButtons.forEach((v) => {
|
||||||
this._c.loadAllButton.onclick = () => {
|
v.onclick = () => this.loadMore(false);
|
||||||
addLoader(this._c.loadAllButton, true);
|
});
|
||||||
this.loadMore(true);
|
this._c.loadAllButtons.forEach((v) => {
|
||||||
};
|
v.onclick = () => this.loadAll();
|
||||||
|
});
|
||||||
/* this._keepSearchingButton.onclick = () => {
|
/* this._keepSearchingButton.onclick = () => {
|
||||||
addLoader(this._keepSearchingButton, true);
|
addLoader(this._keepSearchingButton, true);
|
||||||
this.loadMore(() => removeLoader(this._keepSearchingButton, true));
|
this.loadMore(() => removeLoader(this._keepSearchingButton, true));
|
||||||
@@ -193,7 +198,7 @@ export abstract class PaginatedList {
|
|||||||
|
|
||||||
initSearch = (searchConfig: SearchConfiguration) => {
|
initSearch = (searchConfig: SearchConfiguration) => {
|
||||||
const previousCallback = searchConfig.onSearchCallback;
|
const previousCallback = searchConfig.onSearchCallback;
|
||||||
searchConfig.onSearchCallback = (newItems: boolean, loadAll: boolean) => {
|
searchConfig.onSearchCallback = (newItems: boolean, loadAll: boolean, callback?: (resp: paginatedDTO) => void) => {
|
||||||
// if (this._search.inSearch && !this.lastPage) this._c.loadAllButton.classList.remove("unfocused");
|
// if (this._search.inSearch && !this.lastPage) this._c.loadAllButton.classList.remove("unfocused");
|
||||||
// else this._c.loadAllButton.classList.add("unfocused");
|
// else this._c.loadAllButton.classList.add("unfocused");
|
||||||
|
|
||||||
@@ -206,7 +211,7 @@ export abstract class PaginatedList {
|
|||||||
(this._visible.length == 0 && !this.lastPage) ||
|
(this._visible.length == 0 && !this.lastPage) ||
|
||||||
loadAll
|
loadAll
|
||||||
) {
|
) {
|
||||||
this.loadMore(loadAll);
|
this.loadMore(loadAll, callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this._previousVisibleItemCount = this._visible.length;
|
this._previousVisibleItemCount = this._visible.length;
|
||||||
@@ -390,11 +395,11 @@ export abstract class PaginatedList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Loads the next page. If "loadAll", all pages will be loaded until the last is reached.
|
// Loads the next page. If "loadAll", all pages will be loaded until the last is reached.
|
||||||
public abstract loadMore: (loadAll?: boolean, callback?: () => void) => void;
|
public abstract loadMore: (loadAll?: boolean, callback?: (resp?: paginatedDTO) => void) => void;
|
||||||
protected _loadMore = (loadAll: boolean = false, callback?: (resp: paginatedDTO) => void) => {
|
protected _loadMore = (loadAll: boolean = false, callback?: (resp: paginatedDTO) => void) => {
|
||||||
this._c.loadMoreButton.disabled = true;
|
this._c.loadMoreButtons.forEach((v) => v.disabled = true);
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
this._c.loadMoreButton.disabled = false;
|
this._c.loadMoreButtons.forEach((v) => v.disabled = false);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
this._page += 1;
|
this._page += 1;
|
||||||
|
|
||||||
@@ -406,7 +411,7 @@ export abstract class PaginatedList {
|
|||||||
// Check before setting this.lastPage so we have a chance to cancel the timeout.
|
// Check before setting this.lastPage so we have a chance to cancel the timeout.
|
||||||
if (resp.last_page) {
|
if (resp.last_page) {
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
removeLoader(this._c.loadAllButton);
|
this._c.loadAllButtons.forEach((v) => removeLoader(v));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(resp: paginatedDTO) => {
|
(resp: paginatedDTO) => {
|
||||||
@@ -414,7 +419,7 @@ export abstract class PaginatedList {
|
|||||||
if (this.lastPage) {
|
if (this.lastPage) {
|
||||||
loadAll = false;
|
loadAll = false;
|
||||||
}
|
}
|
||||||
this._search.onSearchBoxChange(true, true, loadAll);
|
this._search.onSearchBoxChange(true, true, loadAll, callback);
|
||||||
} else {
|
} else {
|
||||||
// Since results come to us ordered already, we can assume "ordering"
|
// Since results come to us ordered already, we can assume "ordering"
|
||||||
// will be identical to pre-page-load but with extra elements at the end,
|
// will be identical to pre-page-load but with extra elements at the end,
|
||||||
@@ -427,6 +432,12 @@ export abstract class PaginatedList {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract loadAll: (callback?: (resp?: paginatedDTO) => void) => void;
|
||||||
|
protected _loadAll = (callback?: (resp?: paginatedDTO) => void) => {
|
||||||
|
this._c.loadAllButtons.forEach((v) => { addLoader(v, true); });
|
||||||
|
this.loadMore(true, callback);
|
||||||
|
};
|
||||||
|
|
||||||
loadNItems = (n: number) => {
|
loadNItems = (n: number) => {
|
||||||
const cb = () => {
|
const cb = () => {
|
||||||
if (this._counter.loaded > n) return;
|
if (this._counter.loaded > n) return;
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export interface SearchConfiguration {
|
|||||||
search: HTMLInputElement;
|
search: HTMLInputElement;
|
||||||
queries: { [field: string]: QueryType };
|
queries: { [field: string]: QueryType };
|
||||||
setVisibility: (items: string[], visible: boolean, appendedItems: boolean) => void;
|
setVisibility: (items: string[], visible: boolean, appendedItems: boolean) => void;
|
||||||
onSearchCallback: (newItems: boolean, loadAll: boolean) => void;
|
onSearchCallback: (newItems: boolean, loadAll: boolean, callback?: (resp: paginatedDTO) => void) => void;
|
||||||
searchServer: (params: PaginatedReqDTO, newSearch: boolean) => void;
|
searchServer: (params: PaginatedReqDTO, newSearch: boolean) => void;
|
||||||
clearServerSearch: () => void;
|
clearServerSearch: () => void;
|
||||||
loadMore?: () => void;
|
loadMore?: () => void;
|
||||||
@@ -523,7 +523,7 @@ export class Search {
|
|||||||
get sortField(): string { return this._sortField; }
|
get sortField(): string { return this._sortField; }
|
||||||
get ascending(): boolean { return this._ascending; }
|
get ascending(): boolean { return this._ascending; }
|
||||||
|
|
||||||
onSearchBoxChange = (newItems: boolean = false, appendedItems: boolean = false, loadAll: boolean = false) => {
|
onSearchBoxChange = (newItems: boolean = false, appendedItems: boolean = false, loadAll: boolean = false, callback?: (resp: paginatedDTO) => void) => {
|
||||||
const query = this._c.search.value;
|
const query = this._c.search.value;
|
||||||
if (!query) {
|
if (!query) {
|
||||||
this.inSearch = false;
|
this.inSearch = false;
|
||||||
@@ -532,7 +532,7 @@ export class Search {
|
|||||||
}
|
}
|
||||||
const results = this.search(query);
|
const results = this.search(query);
|
||||||
this._c.setVisibility(results, true, appendedItems);
|
this._c.setVisibility(results, true, appendedItems);
|
||||||
this._c.onSearchCallback(newItems, loadAll);
|
this._c.onSearchCallback(newItems, loadAll, callback);
|
||||||
if (this.inSearch) {
|
if (this.inSearch) {
|
||||||
if (this.inServerSearch) {
|
if (this.inServerSearch) {
|
||||||
this._serverSearchButtons.forEach((v: HTMLElement) => {
|
this._serverSearchButtons.forEach((v: HTMLElement) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user