mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-29 04:22:24 -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, | ||||
| 				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{ | ||||
|  |  | |||
|  | @ -67,9 +67,9 @@ const ( | |||
| 	cssSettings       = distPathPrefix + "/settings-style.css" | ||||
| 	cssTag            = distPathPrefix + "/tag.css" | ||||
| 
 | ||||
| 	jsFrontend = distPathPrefix + "/frontend.js" // Progressive enhancement frontend JS. | ||||
| 	jsBlurhash = distPathPrefix + "/blurhash.js" // Blurhash rendering JS. | ||||
| 	jsSettings = distPathPrefix + "/settings.js" // Settings panel React application. | ||||
| 	jsFrontend          = distPathPrefix + "/frontend.js"           // Progressive enhancement frontend JS. | ||||
| 	jsFrontendPrerender = distPathPrefix + "/frontend_prerender.js" // Frontend JS that should run before page renders. | ||||
| 	jsSettings          = distPathPrefix + "/settings.js"           // Settings panel React application. | ||||
| ) | ||||
| 
 | ||||
| type Module struct { | ||||
|  |  | |||
|  | @ -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: [ | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue