Merge tag 'v4.5.0-beta.1' into chinwag-next

This commit is contained in:
Mike Barnes 2025-10-19 08:48:12 +11:00
commit 24e691a199
938 changed files with 26977 additions and 9177 deletions

View file

@ -1,6 +1,7 @@
import { createRoot } from 'react-dom/client';
import Rails from '@rails/ujs';
import { decode, ValidationError } from 'blurhash';
import ready from '../mastodon/ready';
@ -362,6 +363,46 @@ ready(() => {
document.querySelectorAll('[data-admin-component]').forEach((element) => {
void mountReactComponent(element);
});
document
.querySelectorAll<HTMLCanvasElement>('canvas[data-blurhash]')
.forEach((canvas) => {
const blurhash = canvas.dataset.blurhash;
if (blurhash) {
try {
// decode returns a Uint8ClampedArray<ArrayBufferLike> not Uint8ClampedArray<ArrayBuffer>
const pixels = decode(
blurhash,
32,
32,
) as Uint8ClampedArray<ArrayBuffer>;
const ctx = canvas.getContext('2d');
const imageData = new ImageData(pixels, 32, 32);
ctx?.putImageData(imageData, 0, 0);
} catch (err) {
if (err instanceof ValidationError) {
// ignore blurhash validation errors
return;
}
throw err;
}
}
});
document
.querySelectorAll<HTMLDivElement>('.preview-card')
.forEach((previewCard) => {
const spoilerButton = previewCard.querySelector('.spoiler-button');
if (!spoilerButton) {
return;
}
spoilerButton.addEventListener('click', () => {
previewCard.classList.toggle('preview-card--image-visible');
});
});
}).catch((reason: unknown) => {
throw reason;
});

View file

@ -70,7 +70,7 @@ function loaded() {
};
document.querySelectorAll('.emojify').forEach((content) => {
content.innerHTML = emojify(content.innerHTML);
content.innerHTML = emojify(content.innerHTML, {}, true); // Force emojify as public doesn't load the new emoji system.
});
document
@ -145,6 +145,10 @@ function loaded() {
);
});
updateDefaultQuotePrivacyFromPrivacy(
document.querySelector('#user_settings_attributes_default_privacy'),
);
const reactComponents = document.querySelectorAll('[data-component]');
if (reactComponents.length > 0) {
@ -347,6 +351,31 @@ const setInputDisabled = (
}
};
const setInputHint = (
input: HTMLInputElement | HTMLSelectElement,
hintPrefix: string,
) => {
const fieldWrapper = input.closest<HTMLElement>('.fields-group > .input');
if (!fieldWrapper) return;
const hint = fieldWrapper.dataset[`${hintPrefix}Hint`];
const hintElement =
fieldWrapper.querySelector<HTMLSpanElement>(':scope > .hint');
if (hint) {
if (hintElement) {
hintElement.textContent = hint;
} else {
const newHintElement = document.createElement('span');
newHintElement.className = 'hint';
newHintElement.textContent = hint;
fieldWrapper.appendChild(newHintElement);
}
} else {
hintElement?.remove();
}
};
Rails.delegate(
document,
'#account_statuses_cleanup_policy_enabled',
@ -364,6 +393,36 @@ Rails.delegate(
},
);
const updateDefaultQuotePrivacyFromPrivacy = (
privacySelect: EventTarget | null,
) => {
if (!(privacySelect instanceof HTMLSelectElement) || !privacySelect.form)
return;
const select = privacySelect.form.querySelector<HTMLSelectElement>(
'select#user_settings_attributes_default_quote_policy',
);
if (!select) return;
setInputHint(select, privacySelect.value);
if (privacySelect.value === 'private') {
select.value = 'nobody';
setInputDisabled(select, true);
} else {
setInputDisabled(select, false);
}
};
Rails.delegate(
document,
'#user_settings_attributes_default_privacy',
'change',
({ target }) => {
updateDefaultQuotePrivacyFromPrivacy(target);
},
);
// Empty the honeypot fields in JS in case something like an extension
// automatically filled them.
Rails.delegate(document, '#registration_new_user,#new_user', 'submit', () => {