mirror of
https://github.com/superseriousbusiness/gotosocial
synced 2025-06-05 21:59:39 +02:00
[chore/frontend] Reorder JS a little bit to avoid visible text changes (#4039)
This commit is contained in:
@ -249,7 +249,7 @@ func (m *Module) profileMicroblog(c *gin.Context, p *profile) {
|
||||
},
|
||||
{
|
||||
Bottom: true,
|
||||
Src: jsBlurhash,
|
||||
Src: jsFrontendPrerender,
|
||||
},
|
||||
},
|
||||
Extra: map[string]any{
|
||||
@ -323,7 +323,7 @@ func (m *Module) profileGallery(c *gin.Context, p *profile) {
|
||||
},
|
||||
{
|
||||
Bottom: true,
|
||||
Src: jsBlurhash,
|
||||
Src: jsFrontendPrerender,
|
||||
},
|
||||
},
|
||||
Extra: map[string]any{
|
||||
|
@ -154,7 +154,7 @@ func (m *Module) threadGETHandler(c *gin.Context) {
|
||||
},
|
||||
{
|
||||
Bottom: true,
|
||||
Src: jsBlurhash,
|
||||
Src: jsFrontendPrerender,
|
||||
},
|
||||
},
|
||||
Extra: map[string]any{
|
||||
|
@ -68,7 +68,7 @@ const (
|
||||
cssTag = distPathPrefix + "/tag.css"
|
||||
|
||||
jsFrontend = distPathPrefix + "/frontend.js" // Progressive enhancement frontend JS.
|
||||
jsBlurhash = distPathPrefix + "/blurhash.js" // Blurhash rendering JS.
|
||||
jsFrontendPrerender = distPathPrefix + "/frontend_prerender.js" // Frontend JS that should run before page renders.
|
||||
jsSettings = distPathPrefix + "/settings.js" // Settings panel React application.
|
||||
)
|
||||
|
||||
|
@ -17,6 +17,15 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
WHAT SHOULD GO IN THIS FILE?
|
||||
|
||||
This script is loaded in the document head, and deferred + async,
|
||||
so it's *usually* run after the user is already looking at the page.
|
||||
Put stuff in here that doesn't shift the layout, and it doesn't really
|
||||
matter whether it loads immediately. So, progressive enhancement stuff.
|
||||
*/
|
||||
|
||||
const Photoswipe = require("photoswipe/dist/umd/photoswipe.umd.min.js");
|
||||
const PhotoswipeLightbox = require("photoswipe/dist/umd/photoswipe-lightbox.umd.min.js");
|
||||
const PhotoswipeCaptionPlugin = require("photoswipe-dynamic-caption-plugin").default;
|
||||
@ -165,89 +174,6 @@ lightbox.on('uiRegister', function() {
|
||||
|
||||
lightbox.init();
|
||||
|
||||
function dynamicSpoiler(className, updateFunc) {
|
||||
Array.from(document.getElementsByClassName(className)).forEach((spoiler) => {
|
||||
const update = updateFunc(spoiler);
|
||||
if (update) {
|
||||
update();
|
||||
spoiler.addEventListener("toggle", update);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
dynamicSpoiler("text-spoiler", (details) => {
|
||||
const summary = details.children[0];
|
||||
const button = details.querySelector(".button");
|
||||
|
||||
// Use button *instead of summary*
|
||||
// to toggle post visibility.
|
||||
summary.tabIndex = "-1";
|
||||
button.tabIndex = "0";
|
||||
button.setAttribute("aria-role", "button");
|
||||
button.onclick = (e) => {
|
||||
e.preventDefault();
|
||||
return details.hasAttribute("open")
|
||||
? details.removeAttribute("open")
|
||||
: details.setAttribute("open", "");
|
||||
};
|
||||
|
||||
// Let enter also trigger the button
|
||||
// (for those using keyboard to navigate).
|
||||
button.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
button.click();
|
||||
}
|
||||
});
|
||||
|
||||
// Change button text depending on
|
||||
// whether spoiler is open or closed rn.
|
||||
return () => {
|
||||
button.textContent = details.open
|
||||
? "Show less"
|
||||
: "Show more";
|
||||
};
|
||||
});
|
||||
|
||||
dynamicSpoiler("media-spoiler", (details) => {
|
||||
const summary = details.children[0];
|
||||
const button = details.querySelector(".eye.button");
|
||||
const video = details.querySelector(".plyr-video");
|
||||
const loopingAuto = !reduceMotion.matches && video != null && video.classList.contains("gifv");
|
||||
|
||||
// Use button *instead of summary*
|
||||
// to toggle media visibility.
|
||||
summary.tabIndex = "-1";
|
||||
button.tabIndex = "0";
|
||||
button.setAttribute("aria-role", "button");
|
||||
button.onclick = (e) => {
|
||||
e.preventDefault();
|
||||
return details.hasAttribute("open")
|
||||
? details.removeAttribute("open")
|
||||
: details.setAttribute("open", "");
|
||||
};
|
||||
|
||||
// Let enter also trigger the button
|
||||
// (for those using keyboard to navigate).
|
||||
button.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
button.click();
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
if (details.open) {
|
||||
button.setAttribute("aria-label", "Hide media");
|
||||
} else {
|
||||
button.setAttribute("aria-label", "Show media");
|
||||
if (video && !loopingAuto) {
|
||||
video.pause();
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
Array.from(document.getElementsByClassName("plyr-video")).forEach((video) => {
|
||||
const loopingAuto = !reduceMotion.matches && video.classList.contains("gifv");
|
||||
let player = new Plyr(video, {
|
||||
@ -315,30 +241,6 @@ function inLightbox(element) {
|
||||
lightbox.pswp.currSlide.data.attachmentId;
|
||||
}
|
||||
|
||||
// Define + reuse one DateTimeFormat (cheaper).
|
||||
const dateTimeFormat = Intl.DateTimeFormat(
|
||||
undefined,
|
||||
{
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
hour12: false
|
||||
},
|
||||
);
|
||||
|
||||
// Reformat time text to browser locale.
|
||||
Array.from(document.getElementsByTagName('time')).forEach(timeTag => {
|
||||
const datetime = timeTag.getAttribute('datetime');
|
||||
const currentText = timeTag.textContent.trim();
|
||||
// Only format if current text contains precise time.
|
||||
if (currentText.match(/\d{2}:\d{2}/)) {
|
||||
const date = new Date(datetime);
|
||||
timeTag.textContent = dateTimeFormat.format(date);
|
||||
}
|
||||
});
|
||||
|
||||
// When clicking anywhere that's not an open
|
||||
// stats-info-more-content details dropdown,
|
||||
// close that open dropdown.
|
||||
|
@ -17,8 +17,18 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
WHAT SHOULD GO IN THIS FILE?
|
||||
|
||||
This script is loaded just before the end of the HTML body, so
|
||||
put stuff in here that should be run *before* the user sees the page.
|
||||
So, stuff that shifts the layout or causes elements to jump around.
|
||||
*/
|
||||
|
||||
import { decode } from "blurhash";
|
||||
|
||||
const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
|
||||
|
||||
// Generate a blurhash canvas for each image for
|
||||
// each blurhash container and put it in the summary.
|
||||
Array.from(document.getElementsByClassName('blurhash-container')).forEach(blurhashContainer => {
|
||||
@ -144,3 +154,110 @@ Array.from(document.getElementsByTagName('img')).forEach(img => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Change the spoiler / content warning boxes from generic
|
||||
// "toggle visibility" to show/hide depending on state,
|
||||
// and add keyboard functionality to spoiler buttons.
|
||||
function dynamicSpoiler(className, updateFunc) {
|
||||
Array.from(document.getElementsByClassName(className)).forEach((spoiler) => {
|
||||
const update = updateFunc(spoiler);
|
||||
if (update) {
|
||||
update();
|
||||
spoiler.addEventListener("toggle", update);
|
||||
}
|
||||
});
|
||||
}
|
||||
dynamicSpoiler("text-spoiler", (details) => {
|
||||
const summary = details.children[0];
|
||||
const button = details.querySelector(".button");
|
||||
|
||||
// Use button *instead of summary*
|
||||
// to toggle post visibility.
|
||||
summary.tabIndex = "-1";
|
||||
button.tabIndex = "0";
|
||||
button.setAttribute("aria-role", "button");
|
||||
button.onclick = (e) => {
|
||||
e.preventDefault();
|
||||
return details.hasAttribute("open")
|
||||
? details.removeAttribute("open")
|
||||
: details.setAttribute("open", "");
|
||||
};
|
||||
|
||||
// Let enter also trigger the button
|
||||
// (for those using keyboard to navigate).
|
||||
button.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
button.click();
|
||||
}
|
||||
});
|
||||
|
||||
// Change button text depending on
|
||||
// whether spoiler is open or closed rn.
|
||||
return () => {
|
||||
button.textContent = details.open
|
||||
? "Show less"
|
||||
: "Show more";
|
||||
};
|
||||
});
|
||||
dynamicSpoiler("media-spoiler", (details) => {
|
||||
const summary = details.children[0];
|
||||
const button = details.querySelector(".eye.button");
|
||||
const video = details.querySelector(".plyr-video");
|
||||
const loopingAuto = !reduceMotion.matches && video != null && video.classList.contains("gifv");
|
||||
|
||||
// Use button *instead of summary*
|
||||
// to toggle media visibility.
|
||||
summary.tabIndex = "-1";
|
||||
button.tabIndex = "0";
|
||||
button.setAttribute("aria-role", "button");
|
||||
button.onclick = (e) => {
|
||||
e.preventDefault();
|
||||
return details.hasAttribute("open")
|
||||
? details.removeAttribute("open")
|
||||
: details.setAttribute("open", "");
|
||||
};
|
||||
|
||||
// Let enter also trigger the button
|
||||
// (for those using keyboard to navigate).
|
||||
button.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
button.click();
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
if (details.open) {
|
||||
button.setAttribute("aria-label", "Hide media");
|
||||
} else {
|
||||
button.setAttribute("aria-label", "Show media");
|
||||
if (video && !loopingAuto) {
|
||||
video.pause();
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// Reformat time text to browser locale.
|
||||
// Define + reuse one DateTimeFormat (cheaper).
|
||||
const dateTimeFormat = Intl.DateTimeFormat(
|
||||
undefined,
|
||||
{
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
hour12: false
|
||||
},
|
||||
);
|
||||
Array.from(document.getElementsByTagName('time')).forEach(timeTag => {
|
||||
const datetime = timeTag.getAttribute('datetime');
|
||||
const currentText = timeTag.textContent.trim();
|
||||
// Only format if current text contains precise time.
|
||||
if (currentText.match(/\d{2}:\d{2}/)) {
|
||||
const date = new Date(datetime);
|
||||
timeTag.textContent = dateTimeFormat.format(date);
|
||||
}
|
||||
});
|
@ -64,9 +64,9 @@ skulk({
|
||||
}]
|
||||
],
|
||||
},
|
||||
blurhash: {
|
||||
entryFile: "blurhash",
|
||||
outputFile: "blurhash.js",
|
||||
frontend_prerender: {
|
||||
entryFile: "frontend_prerender",
|
||||
outputFile: "frontend_prerender.js",
|
||||
preset: ["js"],
|
||||
prodCfg: prodCfg,
|
||||
transform: [
|
||||
|
Reference in New Issue
Block a user