mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-11-23 11:22:33 +01:00
Merge branch 'v23.02-branch' into development
This commit is contained in:
commit
50f3c10f19
9
.github/translators.txt
vendored
9
.github/translators.txt
vendored
@ -311,3 +311,12 @@ m4tthi4s :: French
|
||||
toras9000 :: Japanese
|
||||
pathab :: German
|
||||
MichelSchoon85 :: Dutch
|
||||
Jøran Haugli (haugli92) :: Norwegian Bokmal
|
||||
Vasileios Kouvelis (VasilisKouvelis) :: Greek
|
||||
Dremski :: Bulgarian
|
||||
Frédéric SENE (nothingfr) :: French
|
||||
bendem :: French
|
||||
kostasdizas :: Greek
|
||||
Ricardo Schroeder (brownstone666) :: Portuguese, Brazilian
|
||||
Eitan MG (EitanMG) :: Hebrew
|
||||
Robin Flikkema (RobinFlikkema) :: Dutch
|
||||
|
@ -11,11 +11,9 @@ use Illuminate\Support\Facades\DB;
|
||||
|
||||
class TagRepo
|
||||
{
|
||||
protected PermissionApplicator $permissions;
|
||||
|
||||
public function __construct(PermissionApplicator $permissions)
|
||||
{
|
||||
$this->permissions = $permissions;
|
||||
public function __construct(
|
||||
protected PermissionApplicator $permissions
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
@ -90,6 +88,7 @@ class TagRepo
|
||||
{
|
||||
$query = Tag::query()
|
||||
->select('*', DB::raw('count(*) as count'))
|
||||
->where('value', '!=', '')
|
||||
->groupBy('value');
|
||||
|
||||
if ($searchTerm) {
|
||||
|
@ -8,11 +8,9 @@ use Illuminate\Http\Request;
|
||||
|
||||
class TagController extends Controller
|
||||
{
|
||||
protected TagRepo $tagRepo;
|
||||
|
||||
public function __construct(TagRepo $tagRepo)
|
||||
{
|
||||
$this->tagRepo = $tagRepo;
|
||||
public function __construct(
|
||||
protected TagRepo $tagRepo
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -197,7 +197,7 @@ class UserController extends Controller
|
||||
$this->checkPermissionOrCurrentUser('users-manage', $id);
|
||||
|
||||
$user = $this->userRepo->getById($id);
|
||||
$newOwnerId = $request->get('new_owner_id', null);
|
||||
$newOwnerId = intval($request->get('new_owner_id')) ?: null;
|
||||
|
||||
$this->userRepo->destroy($user, $newOwnerId);
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import {escapeHtml} from "../services/util";
|
||||
import {onChildEvent} from "../services/dom";
|
||||
import {Component} from "./component";
|
||||
import {KeyboardNavigationHandler} from "../services/keyboard-navigation";
|
||||
|
||||
const ajaxCache = {};
|
||||
|
||||
@ -21,26 +22,31 @@ export class AutoSuggest extends Component {
|
||||
}
|
||||
|
||||
setupListeners() {
|
||||
const navHandler = new KeyboardNavigationHandler(
|
||||
this.list,
|
||||
event => {
|
||||
this.input.focus();
|
||||
setTimeout(() => this.hideSuggestions(), 1);
|
||||
},
|
||||
event => {
|
||||
event.preventDefault();
|
||||
this.selectSuggestion(event.target.textContent);
|
||||
},
|
||||
);
|
||||
navHandler.shareHandlingToEl(this.input);
|
||||
|
||||
onChildEvent(this.list, '.text-item', 'click', (event, el) => {
|
||||
this.selectSuggestion(el.textContent);
|
||||
});
|
||||
|
||||
this.input.addEventListener('input', this.requestSuggestions.bind(this));
|
||||
this.input.addEventListener('focus', this.requestSuggestions.bind(this));
|
||||
this.input.addEventListener('blur', this.hideSuggestionsIfFocusedLost.bind(this));
|
||||
this.input.addEventListener('keydown', event => {
|
||||
if (event.key === 'Tab') {
|
||||
this.hideSuggestions();
|
||||
}
|
||||
});
|
||||
|
||||
this.input.addEventListener('blur', this.hideSuggestionsIfFocusedLost.bind(this));
|
||||
this.container.addEventListener('keydown', this.containerKeyDown.bind(this));
|
||||
|
||||
onChildEvent(this.list, 'button', 'click', (event, el) => {
|
||||
this.selectSuggestion(el.textContent);
|
||||
});
|
||||
onChildEvent(this.list, 'button', 'keydown', (event, el) => {
|
||||
if (event.key === 'Enter') {
|
||||
this.selectSuggestion(el.textContent);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
selectSuggestion(value) {
|
||||
@ -52,36 +58,6 @@ export class AutoSuggest extends Component {
|
||||
this.hideSuggestions();
|
||||
}
|
||||
|
||||
containerKeyDown(event) {
|
||||
if (event.key === 'Enter') event.preventDefault();
|
||||
if (this.list.classList.contains('hidden')) return;
|
||||
|
||||
// Down arrow
|
||||
if (event.key === 'ArrowDown') {
|
||||
this.moveFocus(true);
|
||||
event.preventDefault();
|
||||
}
|
||||
// Up Arrow
|
||||
else if (event.key === 'ArrowUp') {
|
||||
this.moveFocus(false);
|
||||
event.preventDefault();
|
||||
}
|
||||
// Escape key
|
||||
else if (event.key === 'Escape') {
|
||||
this.hideSuggestions();
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
moveFocus(forward = true) {
|
||||
const focusables = Array.from(this.container.querySelectorAll('input,button'));
|
||||
const index = focusables.indexOf(document.activeElement);
|
||||
const newFocus = focusables[index + (forward ? 1 : -1)];
|
||||
if (newFocus) {
|
||||
newFocus.focus()
|
||||
}
|
||||
}
|
||||
|
||||
async requestSuggestions() {
|
||||
if (Date.now() - this.lastPopulated < 50) {
|
||||
return;
|
||||
@ -132,9 +108,11 @@ export class AutoSuggest extends Component {
|
||||
return this.hideSuggestions();
|
||||
}
|
||||
|
||||
this.list.innerHTML = suggestions.map(value => `<li><button type="button" class="text-item">${escapeHtml(value)}</button></li>`).join('');
|
||||
// This used to use <button>s but was changed to div elements since Safari would not focus on buttons
|
||||
// on which causes a range of other complexities related to focus handling.
|
||||
this.list.innerHTML = suggestions.map(value => `<li><div tabindex="0" class="text-item">${escapeHtml(value)}</div></li>`).join('');
|
||||
this.list.style.display = 'block';
|
||||
for (const button of this.list.querySelectorAll('button')) {
|
||||
for (const button of this.list.querySelectorAll('.text-item')) {
|
||||
button.addEventListener('blur', this.hideSuggestionsIfFocusedLost.bind(this));
|
||||
}
|
||||
}
|
||||
|
@ -162,6 +162,16 @@ class UserManagementTest extends TestCase
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_delete_with_empty_owner_migration_id_works()
|
||||
{
|
||||
$user = $this->users->editor();
|
||||
|
||||
$resp = $this->asAdmin()->delete("settings/users/{$user->id}", ['new_owner_id' => '']);
|
||||
$resp->assertRedirect('/settings/users');
|
||||
$this->assertActivityExists(ActivityType::USER_DELETE);
|
||||
$this->assertSessionHas('success');
|
||||
}
|
||||
|
||||
public function test_delete_removes_user_preferences()
|
||||
{
|
||||
$editor = $this->users->editor();
|
||||
|
Loading…
Reference in New Issue
Block a user