Merge branch 'v23.02-branch' into development

This commit is contained in:
Dan Brown 2023-04-07 18:12:00 +01:00
commit 50f3c10f19
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
6 changed files with 50 additions and 56 deletions

View File

@ -311,3 +311,12 @@ m4tthi4s :: French
toras9000 :: Japanese toras9000 :: Japanese
pathab :: German pathab :: German
MichelSchoon85 :: Dutch 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

View File

@ -11,11 +11,9 @@ use Illuminate\Support\Facades\DB;
class TagRepo class TagRepo
{ {
protected PermissionApplicator $permissions; public function __construct(
protected PermissionApplicator $permissions
public function __construct(PermissionApplicator $permissions) ) {
{
$this->permissions = $permissions;
} }
/** /**
@ -90,6 +88,7 @@ class TagRepo
{ {
$query = Tag::query() $query = Tag::query()
->select('*', DB::raw('count(*) as count')) ->select('*', DB::raw('count(*) as count'))
->where('value', '!=', '')
->groupBy('value'); ->groupBy('value');
if ($searchTerm) { if ($searchTerm) {

View File

@ -8,11 +8,9 @@ use Illuminate\Http\Request;
class TagController extends Controller class TagController extends Controller
{ {
protected TagRepo $tagRepo; public function __construct(
protected TagRepo $tagRepo
public function __construct(TagRepo $tagRepo) ) {
{
$this->tagRepo = $tagRepo;
} }
/** /**

View File

@ -197,7 +197,7 @@ class UserController extends Controller
$this->checkPermissionOrCurrentUser('users-manage', $id); $this->checkPermissionOrCurrentUser('users-manage', $id);
$user = $this->userRepo->getById($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); $this->userRepo->destroy($user, $newOwnerId);

View File

@ -1,6 +1,7 @@
import {escapeHtml} from "../services/util"; import {escapeHtml} from "../services/util";
import {onChildEvent} from "../services/dom"; import {onChildEvent} from "../services/dom";
import {Component} from "./component"; import {Component} from "./component";
import {KeyboardNavigationHandler} from "../services/keyboard-navigation";
const ajaxCache = {}; const ajaxCache = {};
@ -21,26 +22,31 @@ export class AutoSuggest extends Component {
} }
setupListeners() { 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('input', this.requestSuggestions.bind(this));
this.input.addEventListener('focus', 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 => { this.input.addEventListener('keydown', event => {
if (event.key === 'Tab') { if (event.key === 'Tab') {
this.hideSuggestions(); 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) { selectSuggestion(value) {
@ -52,36 +58,6 @@ export class AutoSuggest extends Component {
this.hideSuggestions(); 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() { async requestSuggestions() {
if (Date.now() - this.lastPopulated < 50) { if (Date.now() - this.lastPopulated < 50) {
return; return;
@ -132,9 +108,11 @@ export class AutoSuggest extends Component {
return this.hideSuggestions(); 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'; 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)); button.addEventListener('blur', this.hideSuggestionsIfFocusedLost.bind(this));
} }
} }

View File

@ -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() public function test_delete_removes_user_preferences()
{ {
$editor = $this->users->editor(); $editor = $this->users->editor();