mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 22:32:25 -05:00 
			
		
		
		
	[chore/frontend] Reorder JS a little bit to avoid visible text changes
This commit is contained in:
		
					parent
					
						
							
								a87be80c90
							
						
					
				
			
			
				commit
				
					
						ec4241bb3d
					
				
			
		
					 6 changed files with 135 additions and 116 deletions
				
			
		|  | @ -249,7 +249,7 @@ func (m *Module) profileMicroblog(c *gin.Context, p *profile) { | ||||||
| 			}, | 			}, | ||||||
| 			{ | 			{ | ||||||
| 				Bottom: true, | 				Bottom: true, | ||||||
| 				Src:    jsBlurhash, | 				Src:    jsFrontendPrerender, | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 		Extra: map[string]any{ | 		Extra: map[string]any{ | ||||||
|  | @ -323,7 +323,7 @@ func (m *Module) profileGallery(c *gin.Context, p *profile) { | ||||||
| 			}, | 			}, | ||||||
| 			{ | 			{ | ||||||
| 				Bottom: true, | 				Bottom: true, | ||||||
| 				Src:    jsBlurhash, | 				Src:    jsFrontendPrerender, | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 		Extra: map[string]any{ | 		Extra: map[string]any{ | ||||||
|  |  | ||||||
|  | @ -154,7 +154,7 @@ func (m *Module) threadGETHandler(c *gin.Context) { | ||||||
| 			}, | 			}, | ||||||
| 			{ | 			{ | ||||||
| 				Bottom: true, | 				Bottom: true, | ||||||
| 				Src:    jsBlurhash, | 				Src:    jsFrontendPrerender, | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 		Extra: map[string]any{ | 		Extra: map[string]any{ | ||||||
|  |  | ||||||
|  | @ -67,9 +67,9 @@ const ( | ||||||
| 	cssSettings       = distPathPrefix + "/settings-style.css" | 	cssSettings       = distPathPrefix + "/settings-style.css" | ||||||
| 	cssTag            = distPathPrefix + "/tag.css" | 	cssTag            = distPathPrefix + "/tag.css" | ||||||
| 
 | 
 | ||||||
| 	jsFrontend = distPathPrefix + "/frontend.js" // Progressive enhancement frontend JS. | 	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. | 	jsSettings          = distPathPrefix + "/settings.js"           // Settings panel React application. | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type Module struct { | type Module struct { | ||||||
|  |  | ||||||
|  | @ -17,6 +17,15 @@ | ||||||
| 	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 	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 Photoswipe = require("photoswipe/dist/umd/photoswipe.umd.min.js"); | ||||||
| const PhotoswipeLightbox = require("photoswipe/dist/umd/photoswipe-lightbox.umd.min.js"); | const PhotoswipeLightbox = require("photoswipe/dist/umd/photoswipe-lightbox.umd.min.js"); | ||||||
| const PhotoswipeCaptionPlugin = require("photoswipe-dynamic-caption-plugin").default; | const PhotoswipeCaptionPlugin = require("photoswipe-dynamic-caption-plugin").default; | ||||||
|  | @ -165,89 +174,6 @@ lightbox.on('uiRegister', function() { | ||||||
| 
 | 
 | ||||||
| lightbox.init(); | 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) => { | Array.from(document.getElementsByClassName("plyr-video")).forEach((video) => { | ||||||
| 	const loopingAuto = !reduceMotion.matches && video.classList.contains("gifv"); | 	const loopingAuto = !reduceMotion.matches && video.classList.contains("gifv"); | ||||||
| 	let player = new Plyr(video, { | 	let player = new Plyr(video, { | ||||||
|  | @ -315,30 +241,6 @@ function inLightbox(element) { | ||||||
| 		lightbox.pswp.currSlide.data.attachmentId; | 		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
 | // When clicking anywhere that's not an open
 | ||||||
| // stats-info-more-content details dropdown,
 | // stats-info-more-content details dropdown,
 | ||||||
| // close that open dropdown.
 | // close that open dropdown.
 | ||||||
|  |  | ||||||
|  | @ -17,8 +17,18 @@ | ||||||
| 	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 	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"; | import { decode } from "blurhash"; | ||||||
| 
 | 
 | ||||||
|  | const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)'); | ||||||
|  | 
 | ||||||
| // Generate a blurhash canvas for each image for
 | // Generate a blurhash canvas for each image for
 | ||||||
| // each blurhash container and put it in the summary.
 | // each blurhash container and put it in the summary.
 | ||||||
| Array.from(document.getElementsByClassName('blurhash-container')).forEach(blurhashContainer => { | 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: { | 		frontend_prerender: { | ||||||
| 			entryFile: "blurhash", | 			entryFile: "frontend_prerender", | ||||||
| 			outputFile: "blurhash.js", | 			outputFile: "frontend_prerender.js", | ||||||
| 			preset: ["js"], | 			preset: ["js"], | ||||||
| 			prodCfg: prodCfg, | 			prodCfg: prodCfg, | ||||||
| 			transform: [ | 			transform: [ | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue