Merge branch 'feature/lightbox-carousel' into 'master'
Feature/lightbox-carousel See merge request idotj/mastodon-embed-timeline!32
This commit is contained in:
		
						commit
						164c45bf9e
					
				
							
								
								
									
										10
									
								
								CHANGELOG
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								CHANGELOG
									
									
									
									
									
								
							| @ -1,3 +1,9 @@ | ||||
| v4.3.5 - 09/03/2024 | ||||
| - Add a carousel/lightbox for pictures and videos in a post | ||||
| - Improve data set for media items | ||||
| - Enable loop for videos by default | ||||
| - Small UI improvements | ||||
| 
 | ||||
| v4.3.3 - 01/03/2024 | ||||
| - Fix click conflict on user name | ||||
| - Render emojos in user name | ||||
| @ -58,7 +64,7 @@ v3.13.1 - 12/01/2024 | ||||
| v3.12.0 - 11/12/2023 | ||||
| - Fix link preview event on click | ||||
| 
 | ||||
| v3.11.0 - 4/11/2023 | ||||
| v3.11.0 - 04/11/2023 | ||||
| - Update icons | ||||
| - Improve loader spinner | ||||
| 
 | ||||
| @ -103,7 +109,7 @@ v3.8.1 - 14/08/2023 | ||||
| - Improve JS comments | ||||
| 
 | ||||
| v3.8.0 - 04/08/2023 | ||||
| - Add spoiler/sensitive button for reblog content | ||||
| - Add sensitive/spoiler button for reblog content | ||||
| 
 | ||||
| v3.7.2 - 25/07/2023 | ||||
| - Use window.onload to take async attribute into account | ||||
|  | ||||
							
								
								
									
										23
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								README.md
									
									
									
									
									
								
							| @ -2,7 +2,7 @@ | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| Embed a mastodon timeline in your page, only with a CSS and JS file. | ||||
| Embed a Mastodon timeline in your page, only with a CSS and JS file. | ||||
| 
 | ||||
| Demo running: | ||||
| <https://codepen.io/ipuntoj/pen/MWppNGL> | ||||
| @ -65,11 +65,11 @@ This option allows you to start without the need to upload any files on your ser | ||||
| Copy the following CSS and JS links to include them in your project: | ||||
| 
 | ||||
| ```html | ||||
| <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@idotj/mastodon-embed-timeline@4.3.3/dist/mastodon-timeline.min.css" integrity="sha256-n6277x0TxwslF9uskcdwCPorYZnoSB9Wbv1O1w7Ahds=" crossorigin="anonymous"> | ||||
| <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@idotj/mastodon-embed-timeline@4.3.5/dist/mastodon-timeline.min.css" crossorigin="anonymous"> | ||||
| ``` | ||||
| 
 | ||||
| ```html | ||||
| <script src="https://cdn.jsdelivr.net/npm/@idotj/mastodon-embed-timeline@4.3.3/dist/mastodon-timeline.umd.js" integrity="sha256-H+NYFuLL1tG4+iQmE5LRh5zBg1bToiCK/k4uJi4n3ks=" crossorigin="anonymous"></script> | ||||
| <script src="https://cdn.jsdelivr.net/npm/@idotj/mastodon-embed-timeline@4.3.5/dist/mastodon-timeline.umd.js" crossorigin="anonymous"></script> | ||||
| ``` | ||||
| 
 | ||||
| ### Package manager | ||||
| @ -108,7 +108,7 @@ To get your timeline up add the following HTML structure in your page: | ||||
| </div> | ||||
| ``` | ||||
| 
 | ||||
| Then after that you can initialize the script by running: | ||||
| Now you can then initialize the script running: | ||||
| 
 | ||||
| ```js | ||||
| const myTimeline = new MastodonTimeline.Init(); | ||||
| @ -246,7 +246,7 @@ Here you have all the options available to quickly setup and customize your time | ||||
|   // Default: don't hide | ||||
|   hidePinnedPosts: false, | ||||
| 
 | ||||
|   // Hide user account under the user name | ||||
|   // Hide the user account under the user name | ||||
|   // Default: don't hide | ||||
|   hideUserAccount: false, | ||||
| 
 | ||||
| @ -270,15 +270,24 @@ Here you have all the options available to quickly setup and customize your time | ||||
|   // Default: don't apply | ||||
|   markdownBlockquote: false, | ||||
| 
 | ||||
|   // Show a carousel/lightbox when the user clicks on a picture in a post | ||||
|   // Default: not disabled | ||||
|   disableCarousel: false, | ||||
| 
 | ||||
|   // Customize the text of the buttons used for the carousel/lightbox | ||||
|   carouselCloseTxt: "Close carousel", | ||||
|   carouselPrevTxt: "Previous media item", | ||||
|   carouselNextTxt: "Next media item",   | ||||
| 
 | ||||
|   // Limit the text content to a maximum number of lines | ||||
|   // Default: 0 (unlimited) | ||||
|   txtMaxLines: "0", | ||||
| 
 | ||||
|   // Customize the text of the button used for showing/hiding sensitive/spolier text | ||||
|   // Customize the text of the button used for showing/hiding sensitive/spoiler text | ||||
|   btnShowMore: "SHOW MORE", | ||||
|   btnShowLess: "SHOW LESS", | ||||
| 
 | ||||
|   // Customize the text of the button used for showing sensitive/spolier media content | ||||
|   // Customize the text of the button used for showing sensitive/spoiler media content | ||||
|   btnShowContent: "SHOW CONTENT", | ||||
| 
 | ||||
|   // Customize the text of the button pointing to the Mastodon page placed at the end of the timeline | ||||
|  | ||||
							
								
								
									
										4
									
								
								dist/mastodon-timeline.esm.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								dist/mastodon-timeline.esm.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/mastodon-timeline.min.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								dist/mastodon-timeline.min.css
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										4
									
								
								dist/mastodon-timeline.umd.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								dist/mastodon-timeline.umd.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -60,24 +60,42 @@ | ||||
|         margin: 2rem 0; | ||||
|       } | ||||
| 
 | ||||
|       /* Customized CSS styles */ | ||||
|       /* Example of customized CSS styles */ | ||||
|       .mt-container { | ||||
|         font-family: monospace; | ||||
|         background-color: transparent; | ||||
|         border: 1px solid white; | ||||
|       } | ||||
|       .mt-post { | ||||
|         border-bottom: none; | ||||
|         box-shadow: 2px 2px 6px 2px rgba(0, 0, 0, 0.25); | ||||
|         margin-bottom: 1rem; | ||||
|       } | ||||
|       .mt-post-avatar-image-big img { | ||||
|         border-radius: 0; | ||||
|       } | ||||
|       .mt-container a, | ||||
|       .mt-container a:active, | ||||
|       .mt-container a:link { | ||||
|         color: darkgreen; | ||||
|       } | ||||
|       .mt-post-header { | ||||
|         margin-bottom: 0; | ||||
|       } | ||||
|       .mt-post-avatar-image-big img { | ||||
|         border-radius: 0; | ||||
|       } | ||||
|       .mt-post-header-user { | ||||
|         margin-right: auto; | ||||
|       } | ||||
|       .mt-post-header-date { | ||||
|         position: absolute; | ||||
|         bottom: 1rem; | ||||
|         left: 3.5rem; | ||||
|       } | ||||
|       .mt-post { | ||||
|         border-bottom: none; | ||||
|         box-shadow: 2px 2px 6px 2px rgba(0, 0, 0, 0.25); | ||||
|         margin-bottom: 1rem; | ||||
|         padding-bottom: 2rem; | ||||
|       } | ||||
|       .mt-post-txt, | ||||
|       .mt-post-media-wrapper { | ||||
|         width: calc(100% - 3rem); | ||||
|         margin-left: auto; | ||||
|       } | ||||
|     </style> | ||||
|   </head> | ||||
| 
 | ||||
| @ -105,8 +123,7 @@ | ||||
|         <p> | ||||
|           At JS level, it defaults to the light theme and the date is displayed | ||||
|           in US format using digits only. In order to achieve a minimalist | ||||
|           style, the following options have been changed at its | ||||
|           initialization: | ||||
|           style, the following options have been changed at its initialization: | ||||
|         </p> | ||||
|         <pre> | ||||
|         <code> | ||||
|  | ||||
							
								
								
									
										189
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										189
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -1,12 +1,12 @@ | ||||
| { | ||||
|   "name": "@idotj/mastodon-embed-timeline", | ||||
|   "version": "4.3.3", | ||||
|   "version": "4.3.5", | ||||
|   "lockfileVersion": 3, | ||||
|   "requires": true, | ||||
|   "packages": { | ||||
|     "": { | ||||
|       "name": "@idotj/mastodon-embed-timeline", | ||||
|       "version": "4.3.3", | ||||
|       "version": "4.3.5", | ||||
|       "license": "GNU", | ||||
|       "devDependencies": { | ||||
|         "@rollup/plugin-terser": "^0.4.4", | ||||
| @ -15,14 +15,14 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@jridgewell/gen-mapping": { | ||||
|       "version": "0.3.3", | ||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", | ||||
|       "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", | ||||
|       "version": "0.3.5", | ||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", | ||||
|       "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "@jridgewell/set-array": "^1.0.1", | ||||
|         "@jridgewell/set-array": "^1.2.1", | ||||
|         "@jridgewell/sourcemap-codec": "^1.4.10", | ||||
|         "@jridgewell/trace-mapping": "^0.3.9" | ||||
|         "@jridgewell/trace-mapping": "^0.3.24" | ||||
|       }, | ||||
|       "engines": { | ||||
|         "node": ">=6.0.0" | ||||
| @ -38,9 +38,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@jridgewell/set-array": { | ||||
|       "version": "1.1.2", | ||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", | ||||
|       "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", | ||||
|       "version": "1.2.1", | ||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", | ||||
|       "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", | ||||
|       "dev": true, | ||||
|       "engines": { | ||||
|         "node": ">=6.0.0" | ||||
| @ -63,9 +63,9 @@ | ||||
|       "dev": true | ||||
|     }, | ||||
|     "node_modules/@jridgewell/trace-mapping": { | ||||
|       "version": "0.3.22", | ||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", | ||||
|       "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", | ||||
|       "version": "0.3.24", | ||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.24.tgz", | ||||
|       "integrity": "sha512-+VaWXDa6+l6MhflBvVXjIEAzb59nQ2JUK3bwRp2zRpPtU+8TFRy9Gg/5oIcNlkEL5PGlBFGfemUVvIgLnTzq7Q==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "@jridgewell/resolve-uri": "^3.1.0", | ||||
| @ -94,6 +94,110 @@ | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/@rollup/rollup-android-arm-eabi": { | ||||
|       "version": "4.12.0", | ||||
|       "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.0.tgz", | ||||
|       "integrity": "sha512-+ac02NL/2TCKRrJu2wffk1kZ+RyqxVUlbjSagNgPm94frxtr+XDL12E5Ll1enWskLrtrZ2r8L3wED1orIibV/w==", | ||||
|       "cpu": [ | ||||
|         "arm" | ||||
|       ], | ||||
|       "dev": true, | ||||
|       "optional": true, | ||||
|       "os": [ | ||||
|         "android" | ||||
|       ] | ||||
|     }, | ||||
|     "node_modules/@rollup/rollup-android-arm64": { | ||||
|       "version": "4.12.0", | ||||
|       "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.12.0.tgz", | ||||
|       "integrity": "sha512-OBqcX2BMe6nvjQ0Nyp7cC90cnumt8PXmO7Dp3gfAju/6YwG0Tj74z1vKrfRz7qAv23nBcYM8BCbhrsWqO7PzQQ==", | ||||
|       "cpu": [ | ||||
|         "arm64" | ||||
|       ], | ||||
|       "dev": true, | ||||
|       "optional": true, | ||||
|       "os": [ | ||||
|         "android" | ||||
|       ] | ||||
|     }, | ||||
|     "node_modules/@rollup/rollup-darwin-arm64": { | ||||
|       "version": "4.12.0", | ||||
|       "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.12.0.tgz", | ||||
|       "integrity": "sha512-X64tZd8dRE/QTrBIEs63kaOBG0b5GVEd3ccoLtyf6IdXtHdh8h+I56C2yC3PtC9Ucnv0CpNFJLqKFVgCYe0lOQ==", | ||||
|       "cpu": [ | ||||
|         "arm64" | ||||
|       ], | ||||
|       "dev": true, | ||||
|       "optional": true, | ||||
|       "os": [ | ||||
|         "darwin" | ||||
|       ] | ||||
|     }, | ||||
|     "node_modules/@rollup/rollup-darwin-x64": { | ||||
|       "version": "4.12.0", | ||||
|       "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.12.0.tgz", | ||||
|       "integrity": "sha512-cc71KUZoVbUJmGP2cOuiZ9HSOP14AzBAThn3OU+9LcA1+IUqswJyR1cAJj3Mg55HbjZP6OLAIscbQsQLrpgTOg==", | ||||
|       "cpu": [ | ||||
|         "x64" | ||||
|       ], | ||||
|       "dev": true, | ||||
|       "optional": true, | ||||
|       "os": [ | ||||
|         "darwin" | ||||
|       ] | ||||
|     }, | ||||
|     "node_modules/@rollup/rollup-linux-arm-gnueabihf": { | ||||
|       "version": "4.12.0", | ||||
|       "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.12.0.tgz", | ||||
|       "integrity": "sha512-a6w/Y3hyyO6GlpKL2xJ4IOh/7d+APaqLYdMf86xnczU3nurFTaVN9s9jOXQg97BE4nYm/7Ga51rjec5nfRdrvA==", | ||||
|       "cpu": [ | ||||
|         "arm" | ||||
|       ], | ||||
|       "dev": true, | ||||
|       "optional": true, | ||||
|       "os": [ | ||||
|         "linux" | ||||
|       ] | ||||
|     }, | ||||
|     "node_modules/@rollup/rollup-linux-arm64-gnu": { | ||||
|       "version": "4.12.0", | ||||
|       "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.12.0.tgz", | ||||
|       "integrity": "sha512-0fZBq27b+D7Ar5CQMofVN8sggOVhEtzFUwOwPppQt0k+VR+7UHMZZY4y+64WJ06XOhBTKXtQB/Sv0NwQMXyNAA==", | ||||
|       "cpu": [ | ||||
|         "arm64" | ||||
|       ], | ||||
|       "dev": true, | ||||
|       "optional": true, | ||||
|       "os": [ | ||||
|         "linux" | ||||
|       ] | ||||
|     }, | ||||
|     "node_modules/@rollup/rollup-linux-arm64-musl": { | ||||
|       "version": "4.12.0", | ||||
|       "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.12.0.tgz", | ||||
|       "integrity": "sha512-eTvzUS3hhhlgeAv6bfigekzWZjaEX9xP9HhxB0Dvrdbkk5w/b+1Sxct2ZuDxNJKzsRStSq1EaEkVSEe7A7ipgQ==", | ||||
|       "cpu": [ | ||||
|         "arm64" | ||||
|       ], | ||||
|       "dev": true, | ||||
|       "optional": true, | ||||
|       "os": [ | ||||
|         "linux" | ||||
|       ] | ||||
|     }, | ||||
|     "node_modules/@rollup/rollup-linux-riscv64-gnu": { | ||||
|       "version": "4.12.0", | ||||
|       "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.12.0.tgz", | ||||
|       "integrity": "sha512-ix+qAB9qmrCRiaO71VFfY8rkiAZJL8zQRXveS27HS+pKdjwUfEhqo2+YF2oI+H/22Xsiski+qqwIBxVewLK7sw==", | ||||
|       "cpu": [ | ||||
|         "riscv64" | ||||
|       ], | ||||
|       "dev": true, | ||||
|       "optional": true, | ||||
|       "os": [ | ||||
|         "linux" | ||||
|       ] | ||||
|     }, | ||||
|     "node_modules/@rollup/rollup-linux-x64-gnu": { | ||||
|       "version": "4.12.0", | ||||
|       "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.12.0.tgz", | ||||
| @ -120,6 +224,45 @@ | ||||
|         "linux" | ||||
|       ] | ||||
|     }, | ||||
|     "node_modules/@rollup/rollup-win32-arm64-msvc": { | ||||
|       "version": "4.12.0", | ||||
|       "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.12.0.tgz", | ||||
|       "integrity": "sha512-JPDxovheWNp6d7AHCgsUlkuCKvtu3RB55iNEkaQcf0ttsDU/JZF+iQnYcQJSk/7PtT4mjjVG8N1kpwnI9SLYaw==", | ||||
|       "cpu": [ | ||||
|         "arm64" | ||||
|       ], | ||||
|       "dev": true, | ||||
|       "optional": true, | ||||
|       "os": [ | ||||
|         "win32" | ||||
|       ] | ||||
|     }, | ||||
|     "node_modules/@rollup/rollup-win32-ia32-msvc": { | ||||
|       "version": "4.12.0", | ||||
|       "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.12.0.tgz", | ||||
|       "integrity": "sha512-fjtuvMWRGJn1oZacG8IPnzIV6GF2/XG+h71FKn76OYFqySXInJtseAqdprVTDTyqPxQOG9Exak5/E9Z3+EJ8ZA==", | ||||
|       "cpu": [ | ||||
|         "ia32" | ||||
|       ], | ||||
|       "dev": true, | ||||
|       "optional": true, | ||||
|       "os": [ | ||||
|         "win32" | ||||
|       ] | ||||
|     }, | ||||
|     "node_modules/@rollup/rollup-win32-x64-msvc": { | ||||
|       "version": "4.12.0", | ||||
|       "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.12.0.tgz", | ||||
|       "integrity": "sha512-ZYmr5mS2wd4Dew/JjT0Fqi2NPB/ZhZ2VvPp7SmvPZb4Y1CG/LRcS6tcRo2cYU7zLK5A7cdbhWnnWmUjoI4qapg==", | ||||
|       "cpu": [ | ||||
|         "x64" | ||||
|       ], | ||||
|       "dev": true, | ||||
|       "optional": true, | ||||
|       "os": [ | ||||
|         "win32" | ||||
|       ] | ||||
|     }, | ||||
|     "node_modules/@types/estree": { | ||||
|       "version": "1.0.5", | ||||
|       "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", | ||||
| @ -281,6 +424,20 @@ | ||||
|       "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", | ||||
|       "dev": true | ||||
|     }, | ||||
|     "node_modules/fsevents": { | ||||
|       "version": "2.3.3", | ||||
|       "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", | ||||
|       "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", | ||||
|       "dev": true, | ||||
|       "hasInstallScript": true, | ||||
|       "optional": true, | ||||
|       "os": [ | ||||
|         "darwin" | ||||
|       ], | ||||
|       "engines": { | ||||
|         "node": "^8.16.0 || ^10.6.0 || >=11.0.0" | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/glob": { | ||||
|       "version": "7.2.3", | ||||
|       "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", | ||||
| @ -530,9 +687,9 @@ | ||||
|       } | ||||
|     }, | ||||
|     "node_modules/terser": { | ||||
|       "version": "5.27.1", | ||||
|       "resolved": "https://registry.npmjs.org/terser/-/terser-5.27.1.tgz", | ||||
|       "integrity": "sha512-29wAr6UU/oQpnTw5HoadwjUZnFQXGdOfj0LjZ4sVxzqwHh/QVkvr7m8y9WoR4iN3FRitVduTc6KdjcW38Npsug==", | ||||
|       "version": "5.28.1", | ||||
|       "resolved": "https://registry.npmjs.org/terser/-/terser-5.28.1.tgz", | ||||
|       "integrity": "sha512-wM+bZp54v/E9eRRGXb5ZFDvinrJIOaTapx3WUokyVGZu5ucVCK55zEgGd5Dl2fSr3jUo5sDiERErUWLY6QPFyA==", | ||||
|       "dev": true, | ||||
|       "dependencies": { | ||||
|         "@jridgewell/source-map": "^0.3.3", | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "@idotj/mastodon-embed-timeline", | ||||
|   "version": "4.3.3", | ||||
|   "version": "4.3.5", | ||||
|   "description": "Displays Mastodon timeline with posts embed in your website. Very easy to setup, no dependencies, no trackers, cross-browser, WCAG compliant and fully responsive.", | ||||
|   "license": "GNU", | ||||
|   "author": { | ||||
|  | ||||
| @ -1,10 +1,12 @@ | ||||
| /* Mastodon embed timeline v4.3.3 */ | ||||
| /* Mastodon embed timeline v4.3.5 */ | ||||
| /* More info at: */ | ||||
| /* https://gitlab.com/idotj/mastodon-embed-timeline */ | ||||
| 
 | ||||
| /* Variables */ | ||||
| .mt-container, | ||||
| .mt-container[data-theme="light"] { | ||||
| .mt-dialog, | ||||
| .mt-container[data-theme="light"], | ||||
| .mt-dialog[data-theme="light"] { | ||||
|   --mt-txt-max-lines: none; | ||||
|   --mt-color-bg: #fff; | ||||
|   --mt-color-bg-hover: #d9e1e8; | ||||
| @ -16,8 +18,10 @@ | ||||
|   --mt-color-btn-bg: #6364ff; | ||||
|   --mt-color-btn-bg-hover: #563acc; | ||||
|   --mt-color-btn-txt: #fff; | ||||
|   --mt-color-backdrop: #00000090; | ||||
| } | ||||
| .mt-container[data-theme="dark"] { | ||||
| .mt-container[data-theme="dark"], | ||||
| .mt-dialog[data-theme="dark"] { | ||||
|   --mt-color-bg: #282c37; | ||||
|   --mt-color-bg-hover: #313543; | ||||
|   --mt-color-line-gray: #393f4f; | ||||
| @ -28,11 +32,13 @@ | ||||
| } | ||||
| 
 | ||||
| /* Reset CSS */ | ||||
| .mt-container button { | ||||
| .mt-container button, | ||||
| .mt-dialog button { | ||||
|   font: inherit; | ||||
| } | ||||
| .mt-container a, | ||||
| .mt-container button { | ||||
| .mt-container button, | ||||
| .mt-dialog button { | ||||
|   cursor: pointer; | ||||
| } | ||||
| 
 | ||||
| @ -254,18 +260,30 @@ | ||||
| } | ||||
| 
 | ||||
| /* Medias */ | ||||
| .mt-post-media-wrapper { | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
|   gap: 1rem; | ||||
|   margin-bottom: 1rem; | ||||
| } | ||||
| .mt-post-media { | ||||
|   position: relative; | ||||
|   overflow: hidden; | ||||
|   margin-bottom: 1rem; | ||||
| } | ||||
| .mt-post-media-spoiler > img, | ||||
| .mt-post-media-spoiler > audio, | ||||
| .mt-post-media-spoiler > video, | ||||
| .mt-post-media-spoiler > .mt-post-media-play-icon { | ||||
| .mt-post-media-spoiler > .mt-btn-play { | ||||
|   filter: blur(2rem); | ||||
|   pointer-events: none; | ||||
| } | ||||
| .mt-post-media, | ||||
| .mt-post-media-spoiler > img, | ||||
| .mt-post-media-spoiler > audio, | ||||
| .mt-post-media > img, | ||||
| .mt-post-media > video { | ||||
|   border-radius: 0.5rem; | ||||
| } | ||||
| .mt-post-media > audio { | ||||
|   width: 100%; | ||||
|   position: relative; | ||||
| @ -282,28 +300,93 @@ | ||||
|   text-align: center; | ||||
|   color: var(--mt-color-content-txt); | ||||
| } | ||||
| .mt-post-media.mt-loading-spinner .mt-post-media-play-icon { | ||||
|   display: none; | ||||
| 
 | ||||
| /* Dialog - modal */ | ||||
| body:has(dialog.mt-dialog[open]) { | ||||
|   overflow: hidden; | ||||
| } | ||||
| .mt-post-media-play-icon { | ||||
| .mt-dialog { | ||||
|   display: flex; | ||||
|   position: absolute; | ||||
|   width: 3rem; | ||||
|   height: 3rem; | ||||
|   top: calc(50% - 1.5rem); | ||||
|   left: calc(50% - 1.5rem); | ||||
|   justify-content: center; | ||||
|   flex-direction: column; | ||||
|   align-items: center; | ||||
|   justify-content: center; | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
|   border: none; | ||||
|   color: var(--mt-color-content-txt); | ||||
|   background-color: transparent; | ||||
|   padding: 0; | ||||
|   margin: 1rem; | ||||
|   overflow: hidden; | ||||
| } | ||||
| .mt-dialog::backdrop { | ||||
|   background-color: var(--mt-color-backdrop); | ||||
|   backdrop-filter: blur(8px); | ||||
|   -webkit-backdrop-filter: blur(8px); | ||||
| } | ||||
| 
 | ||||
| /* Carousel/lightbox */ | ||||
| .mt-carousel-header { | ||||
|   position: absolute; | ||||
|   top: 0; | ||||
|   right: 0; | ||||
|   z-index: 2; | ||||
| } | ||||
| .mt-carousel-body { | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
| } | ||||
| .mt-carousel-scroll { | ||||
|   display: flex; | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
|   margin: 0; | ||||
|   padding: 0; | ||||
|   list-style: none; | ||||
|   overflow-x: auto; | ||||
|   overflow-y: hidden; | ||||
|   scroll-snap-type: x mandatory; | ||||
|   scroll-behavior: smooth; | ||||
|   scrollbar-width: none; | ||||
| } | ||||
| .mt-carousel-scroll::-webkit-scrollbar { | ||||
|   display: none; | ||||
|   -webkit-appearance: none; | ||||
| } | ||||
| .mt-carousel-item { | ||||
|   scroll-snap-align: center; | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
| } | ||||
| .mt-carousel-media-wrapper { | ||||
|   width: calc(100vw - 2.5rem); | ||||
|   height: 100%; | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   justify-content: center; | ||||
|   text-align: center; | ||||
| } | ||||
| .mt-carousel-media { | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
|   object-fit: contain; | ||||
|   padding: 2rem; | ||||
| } | ||||
| .mt-carousel-prev, | ||||
| .mt-carousel-next { | ||||
|   position: absolute; | ||||
|   background-color: transparent; | ||||
|   border: none; | ||||
|   cursor: pointer; | ||||
|   padding: 0.5rem; | ||||
|   z-index: 2; | ||||
| } | ||||
| .mt-post-media-play-icon > svg { | ||||
|   width: 2.5rem; | ||||
|   height: 2.5rem; | ||||
|   fill: var(--mt-color-bg); | ||||
|   stroke: var(--mt-color-content-txt); | ||||
|   stroke-width: 1px; | ||||
| .mt-carousel-prev { | ||||
|   left: 0; | ||||
|   padding-left: 0; | ||||
| } | ||||
| .mt-carousel-next { | ||||
|   right: 0; | ||||
|   padding-right: 0; | ||||
| } | ||||
| 
 | ||||
| /* Preview link */ | ||||
| @ -372,7 +455,31 @@ | ||||
| } | ||||
| 
 | ||||
| /* Buttons */ | ||||
| .mt-container .mt-btn-dark { | ||||
| .mt-btn-play { | ||||
|   display: flex; | ||||
|   position: absolute; | ||||
|   width: 3rem; | ||||
|   height: 3rem; | ||||
|   top: calc(50% - 1.5rem); | ||||
|   left: calc(50% - 1.5rem); | ||||
|   justify-content: center; | ||||
|   align-items: center; | ||||
|   background-color: transparent; | ||||
|   border: none; | ||||
|   cursor: pointer; | ||||
| } | ||||
| .mt-btn-play > svg { | ||||
|   width: 2.5rem; | ||||
|   height: 2.5rem; | ||||
|   fill: var(--mt-color-bg); | ||||
|   stroke: var(--mt-color-content-txt); | ||||
|   stroke-width: 1px; | ||||
| } | ||||
| .mt-post-media.mt-loading-spinner .mt-btn-play { | ||||
|   display: none; | ||||
| } | ||||
| .mt-container .mt-btn-dark, | ||||
| .mt-dialog .mt-btn-dark { | ||||
|   display: flex; | ||||
|   border-radius: 0.25rem; | ||||
|   background-color: var(--mt-color-line-gray); | ||||
| @ -381,11 +488,15 @@ | ||||
|   font-weight: 600; | ||||
|   font-size: 0.75rem; | ||||
|   text-align: center; | ||||
|   padding: 0 0.5rem; | ||||
|   padding: 0.25rem 0.5rem; | ||||
|   line-height: 1.25rem; | ||||
| 
 | ||||
|   vertical-align: top; | ||||
| } | ||||
| .mt-dialog .mt-btn-dark { | ||||
|   margin-left: auto; | ||||
| } | ||||
| .mt-dialog .mt-btn-violet, | ||||
| .mt-dialog a.mt-btn-violet, | ||||
| .mt-container .mt-btn-violet, | ||||
| .mt-container a.mt-btn-violet { | ||||
|   display: flex; | ||||
| @ -400,6 +511,8 @@ | ||||
|   background-color: var(--mt-color-btn-bg); | ||||
|   color: var(--mt-color-btn-txt); | ||||
| } | ||||
| .mt-dialog .mt-btn-violet:hover, | ||||
| .mt-dialog a.mt-btn-violet:hover, | ||||
| .mt-container .mt-btn-violet:hover, | ||||
| .mt-container a.mt-btn-violet:hover { | ||||
|   background-color: var(--mt-color-btn-bg-hover); | ||||
| @ -407,6 +520,7 @@ | ||||
| } | ||||
| .mt-post-txt .mt-btn-spoiler { | ||||
|   display: inline-block; | ||||
|   vertical-align: middle; | ||||
| } | ||||
| .mt-post-media.mt-loading-spinner > .mt-btn-spoiler { | ||||
|   display: none; | ||||
| @ -436,6 +550,7 @@ | ||||
| } | ||||
| .mt-error-icon { | ||||
|   font-size: 2rem; | ||||
|   margin-bottom: 1rem; | ||||
| } | ||||
| .mt-error-message { | ||||
|   width: 100%; | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| /** | ||||
|  * Mastodon embed timeline | ||||
|  * @author idotj | ||||
|  * @version 4.3.3 | ||||
|  * @version 4.3.5 | ||||
|  * @url https://gitlab.com/idotj/mastodon-embed-timeline
 | ||||
|  * @license GNU AGPLv3 | ||||
|  */ | ||||
| @ -36,6 +36,10 @@ export class Init { | ||||
|       hidePreviewLink: false, | ||||
|       hideCounterBar: false, | ||||
|       markdownBlockquote: false, | ||||
|       disableCarousel: false, | ||||
|       carouselCloseTxt: "Close carousel", | ||||
|       carouselPrevTxt: "Previous media item", | ||||
|       carouselNextTxt: "Next media item", | ||||
|       txtMaxLines: "0", | ||||
|       btnShowMore: "SHOW MORE", | ||||
|       btnShowLess: "SHOW LESS", | ||||
| @ -172,42 +176,17 @@ export class Init { | ||||
|    * Requests to the server to collect all the data | ||||
|    * @returns {object} Data container | ||||
|    */ | ||||
|   #fetchTimelineData() { | ||||
|   #getTimelineData() { | ||||
|     return new Promise((resolve, reject) => { | ||||
|       /** | ||||
|        * Fetch data from server | ||||
|        * @param {string} url address to fetch | ||||
|        * @returns {array} List of objects | ||||
|        */ | ||||
|       async function fetchData(url) { | ||||
|         const response = await fetch(url); | ||||
| 
 | ||||
|         if (!response.ok) { | ||||
|           throw new Error( | ||||
|             "Failed to fetch the following Url: <br>" + | ||||
|               url + | ||||
|               "<hr>" + | ||||
|               "Error status: " + | ||||
|               response.status + | ||||
|               "<hr>" + | ||||
|               "Error message: " + | ||||
|               response.statusText | ||||
|           ); | ||||
|         } | ||||
| 
 | ||||
|         const data = await response.json(); | ||||
|         return data; | ||||
|       } | ||||
| 
 | ||||
|       // Urls to fetch
 | ||||
|       const instanceApiUrl = `${this.mtSettings.instanceUrl}/api/v1/`; | ||||
|       let urls = {}; | ||||
| 
 | ||||
|       if (this.mtSettings.instanceUrl) { | ||||
|         if (this.mtSettings.timelineType === "profile") { | ||||
|           if (this.mtSettings.userId) { | ||||
|             urls.timeline = `${this.mtSettings.instanceUrl}/api/v1/accounts/${this.mtSettings.userId}/statuses?limit=${this.mtSettings.maxNbPostFetch}`; | ||||
|             urls.timeline = `${instanceApiUrl}accounts/${this.mtSettings.userId}/statuses?limit=${this.mtSettings.maxNbPostFetch}`; | ||||
|             if (!this.mtSettings.hidePinnedPosts) { | ||||
|               urls.pinned = `${this.mtSettings.instanceUrl}/api/v1/accounts/${this.mtSettings.userId}/statuses?pinned=true`; | ||||
|               urls.pinned = `${instanceApiUrl}accounts/${this.mtSettings.userId}/statuses?pinned=true`; | ||||
|             } | ||||
|           } else { | ||||
|             this.#showError( | ||||
| @ -217,7 +196,7 @@ export class Init { | ||||
|           } | ||||
|         } else if (this.mtSettings.timelineType === "hashtag") { | ||||
|           if (this.mtSettings.hashtagName) { | ||||
|             urls.timeline = `${this.mtSettings.instanceUrl}/api/v1/timelines/tag/${this.mtSettings.hashtagName}?limit=${this.mtSettings.maxNbPostFetch}`; | ||||
|             urls.timeline = `${instanceApiUrl}timelines/tag/${this.mtSettings.hashtagName}?limit=${this.mtSettings.maxNbPostFetch}`; | ||||
|           } else { | ||||
|             this.#showError( | ||||
|               "Please check your <strong>hashtagName</strong> value", | ||||
| @ -225,7 +204,7 @@ export class Init { | ||||
|             ); | ||||
|           } | ||||
|         } else if (this.mtSettings.timelineType === "local") { | ||||
|           urls.timeline = `${this.mtSettings.instanceUrl}/api/v1/timelines/public?local=true&limit=${this.mtSettings.maxNbPostFetch}`; | ||||
|           urls.timeline = `${instanceApiUrl}timelines/public?local=true&limit=${this.mtSettings.maxNbPostFetch}`; | ||||
|         } else { | ||||
|           this.#showError( | ||||
|             "Please check your <strong>timelineType</strong> value", | ||||
| @ -239,15 +218,15 @@ export class Init { | ||||
|         ); | ||||
|       } | ||||
|       if (!this.mtSettings.hideEmojos) { | ||||
|         urls.emojos = this.mtSettings.instanceUrl + "/api/v1/custom_emojis"; | ||||
|         urls.emojos = `${instanceApiUrl}custom_emojis`; | ||||
|       } | ||||
| 
 | ||||
|       const urlsPromises = Object.entries(urls).map(([key, url]) => { | ||||
|         return fetchData(url) | ||||
|         return this.#fetchData(url) | ||||
|           .then((data) => ({ [key]: data })) | ||||
|           .catch((error) => { | ||||
|             reject( | ||||
|               new Error("Something went wrong fetching data from: " + url) | ||||
|               new Error(`Something went wrong fetching data from: ${url}`) | ||||
|             ); | ||||
|             this.#showError(error.message); | ||||
|             return { [key]: [] }; | ||||
| @ -266,12 +245,30 @@ export class Init { | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Fetch data from server | ||||
|    * @param {string} url address to fetch | ||||
|    * @returns {array} List of objects | ||||
|    */ | ||||
|   async #fetchData(url) { | ||||
|     const response = await fetch(url); | ||||
| 
 | ||||
|     if (!response.ok) { | ||||
|       throw new Error(` | ||||
|         Failed to fetch the following Url:<br/>${url}<hr>Error status: ${response.status}<hr>Error message: ${response.statusText} | ||||
|         `);
 | ||||
|     } | ||||
| 
 | ||||
|     const data = await response.json(); | ||||
|     return data; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Filter all fetched posts and append them on the timeline | ||||
|    * @param {string} t Type of build (new or reload) | ||||
|    */ | ||||
|   async #buildTimeline(t) { | ||||
|     await this.#fetchTimelineData(); | ||||
|     await this.#getTimelineData(); | ||||
| 
 | ||||
|     // Merge pinned posts with timeline posts
 | ||||
|     let posts; | ||||
| @ -320,10 +317,9 @@ export class Init { | ||||
| 
 | ||||
|     // If there are no posts to display, show an error message
 | ||||
|     if (this.mtBodyNode.innerHTML === "") { | ||||
|       const errorMessage = | ||||
|         "No posts to show <hr/>" + | ||||
|         (posts?.length || 0) + | ||||
|         " posts have been fetched from the server <hr/>This may be due to an incorrect configuration in the parameters or to filters applied (to hide certains type of posts)"; | ||||
|       const errorMessage = `No posts to show<hr/>${ | ||||
|         posts?.length || 0 | ||||
|       } posts have been fetched from the server<hr/>This may be due to an incorrect configuration with the parameters or with the filters applied (to hide certains type of posts)`;
 | ||||
|       this.#showError(errorMessage, "📭"); | ||||
|     } else { | ||||
|       if (t === "newTimeline") { | ||||
| @ -379,14 +375,14 @@ export class Init { | ||||
|         '<img src="' + | ||||
|         c.reblog.account.avatar + | ||||
|         '" alt="' + | ||||
|         this.#escapeHtml(c.reblog.account.username) + | ||||
|         this.#escapeHTML(c.reblog.account.username) + | ||||
|         ' avatar" loading="lazy" />' + | ||||
|         "</div>" + | ||||
|         '<div class="mt-post-avatar-image-small">' + | ||||
|         '<img src="' + | ||||
|         c.account.avatar + | ||||
|         '" alt="' + | ||||
|         this.#escapeHtml(c.account.username) + | ||||
|         this.#escapeHTML(c.account.username) + | ||||
|         ' avatar" loading="lazy" />' + | ||||
|         "</div>" + | ||||
|         "</div>" + | ||||
| @ -399,7 +395,9 @@ export class Init { | ||||
|           c.reblog.account.emojis | ||||
|         ); | ||||
|       } else { | ||||
|         userName = c.reblog.account.display_name ? c.reblog.account.display_name : c.reblog.account.username; | ||||
|         userName = c.reblog.account.display_name | ||||
|           ? c.reblog.account.display_name | ||||
|           : c.reblog.account.username; | ||||
|       } | ||||
| 
 | ||||
|       if (!this.mtSettings.hideUserAccount) { | ||||
| @ -446,7 +444,7 @@ export class Init { | ||||
|         '<img src="' + | ||||
|         c.account.avatar + | ||||
|         '" alt="' + | ||||
|         this.#escapeHtml(c.account.username) + | ||||
|         this.#escapeHTML(c.account.username) + | ||||
|         ' avatar" loading="lazy" />' + | ||||
|         "</div>" + | ||||
|         "</div>" + | ||||
| @ -459,7 +457,9 @@ export class Init { | ||||
|           c.account.emojis | ||||
|         ); | ||||
|       } else { | ||||
|         userName = c.account.display_name ? c.account.display_name : c.account.username; | ||||
|         userName = c.account.display_name | ||||
|           ? c.account.display_name | ||||
|           : c.account.username; | ||||
|       } | ||||
| 
 | ||||
|       if (!this.mtSettings.hideUserAccount) { | ||||
| @ -495,22 +495,20 @@ export class Init { | ||||
| 
 | ||||
|     // Date
 | ||||
|     formattedDate = this.#formatDate(date); | ||||
|     const timestamp = | ||||
|       '<div class="mt-post-header-date">' + | ||||
|       (c.pinned | ||||
|         ? '<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24" class="mt-post-pinned" aria-hidden="true"><path d="m640-480 80 80v80H520v240l-40 40-40-40v-240H240v-80l80-80v-280h-40v-80h400v80h-40v280Zm-286 80h252l-46-46v-314H400v314l-46 46Zm126 0Z"></path></svg>' | ||||
|         : "") + | ||||
|       '<a href="' + | ||||
|       url + | ||||
|       '" rel="nofollow noopener noreferrer" target="_blank">' + | ||||
|       '<time datetime="' + | ||||
|       date + | ||||
|       '">' + | ||||
|       formattedDate + | ||||
|       "</time>" + | ||||
|       (c.edited_at ? " *" : "") + | ||||
|       "</a>" + | ||||
|       "</div>"; | ||||
|     const timestamp = ` | ||||
|       <div class="mt-post-header-date"> | ||||
|         ${ | ||||
|           c.pinned | ||||
|             ? '<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24" class="mt-post-pinned" aria-hidden="true"><path d="m640-480 80 80v80H520v240l-40 40-40-40v-240H240v-80l80-80v-280h-40v-80h400v80h-40v280Zm-286 80h252l-46-46v-314H400v314l-46 46Zm126 0Z"></path></svg>' | ||||
|             : "" | ||||
|         } | ||||
|         <a href="${url}" rel="nofollow noopener noreferrer" target="_blank"> | ||||
|           <time datetime="${date}"> | ||||
|             ${formattedDate} | ||||
|           </time> | ||||
|           ${c.edited_at ? " *" : ""} | ||||
|         </a> | ||||
|       </div>`; | ||||
| 
 | ||||
|     // Main text
 | ||||
|     let txtCss = ""; | ||||
| @ -587,6 +585,7 @@ export class Init { | ||||
|         ); | ||||
|       } | ||||
|     } | ||||
|     media = `<div class="mt-post-media-wrapper">${media.join("")}</div>`; | ||||
| 
 | ||||
|     // Preview link
 | ||||
|     let previewLink = ""; | ||||
| @ -655,7 +654,7 @@ export class Init { | ||||
|       timestamp + | ||||
|       "</div>" + | ||||
|       content + | ||||
|       media.join("") + | ||||
|       media + | ||||
|       previewLink + | ||||
|       poll + | ||||
|       counterBar + | ||||
| @ -743,7 +742,7 @@ export class Init { | ||||
|    * @param {string} s String | ||||
|    * @returns {string} String | ||||
|    */ | ||||
|   #escapeHtml(s) { | ||||
|   #escapeHTML(s) { | ||||
|     return (s ?? "") | ||||
|       .replaceAll("&", "&") | ||||
|       .replaceAll("<", "<") | ||||
| @ -793,7 +792,7 @@ export class Init { | ||||
|   /** | ||||
|    * Create media element | ||||
|    * @param {object} m Media content | ||||
|    * @param {boolean} s Spoiler/Sensitive status | ||||
|    * @param {boolean} s Sensitive/spoiler status | ||||
|    * @returns {string} Media in HTML format | ||||
|    */ | ||||
|   #createMedia(m, s) { | ||||
| @ -806,6 +805,16 @@ export class Init { | ||||
|         '<div class="mt-post-media ' + | ||||
|         (spoiler ? "mt-post-media-spoiler " : "") + | ||||
|         this.mtSettings.spinnerClass + | ||||
|         '" data-media-type="' + | ||||
|         m.type + | ||||
|         '" data-media-url-hd="' + | ||||
|         m.url + | ||||
|         '" data-media-alt-txt="' + | ||||
|         (m.description ? this.#escapeHTML(m.description) : "") + | ||||
|         '" data-media-width-hd="' + | ||||
|         m.meta.original.width + | ||||
|         '" data-media-height-hd="' + | ||||
|         m.meta.original.height + | ||||
|         '" style="padding-top: calc(100%/' + | ||||
|         m.meta.small.aspect + | ||||
|         ')">' + | ||||
| @ -817,7 +826,7 @@ export class Init { | ||||
|         '<img src="' + | ||||
|         m.preview_url + | ||||
|         '" alt="' + | ||||
|         (m.description ? this.#escapeHtml(m.description) : "") + | ||||
|         (m.description ? this.#escapeHTML(m.description) : "") + | ||||
|         '" loading="lazy" />' + | ||||
|         "</div>"; | ||||
|     } | ||||
| @ -828,6 +837,16 @@ export class Init { | ||||
|           '<div class="mt-post-media ' + | ||||
|           (spoiler ? "mt-post-media-spoiler " : "") + | ||||
|           this.mtSettings.spinnerClass + | ||||
|           '" data-media-type="' + | ||||
|           m.type + | ||||
|           '" data-media-url-hd="' + | ||||
|           m.preview_url + | ||||
|           '" data-media-alt-txt="' + | ||||
|           (m.description ? this.#escapeHTML(m.description) : "") + | ||||
|           '" data-media-width-hd="' + | ||||
|           m.meta.small.width + | ||||
|           '" data-media-height-hd="' + | ||||
|           m.meta.small.height + | ||||
|           '" style="padding-top: calc(100%/' + | ||||
|           m.meta.small.aspect + | ||||
|           ')">' + | ||||
| @ -842,13 +861,15 @@ export class Init { | ||||
|           '<img src="' + | ||||
|           m.preview_url + | ||||
|           '" alt="' + | ||||
|           (m.description ? this.#escapeHtml(m.description) : "") + | ||||
|           (m.description ? this.#escapeHTML(m.description) : "") + | ||||
|           '" loading="lazy" />' + | ||||
|           "</div>"; | ||||
|       } else { | ||||
|         media = | ||||
|           '<div class="mt-post-media ' + | ||||
|           (spoiler ? "mt-post-media-spoiler " : "") + | ||||
|           '" data-media-type="' + | ||||
|           m.type + | ||||
|           '">' + | ||||
|           (spoiler | ||||
|             ? '<button class="mt-btn-dark mt-btn-spoiler">' + | ||||
| @ -868,8 +889,16 @@ export class Init { | ||||
|           '<div class="mt-post-media ' + | ||||
|           (spoiler ? "mt-post-media-spoiler " : "") + | ||||
|           this.mtSettings.spinnerClass + | ||||
|           '" data-video-url="' + | ||||
|           '" data-media-type="' + | ||||
|           m.type + | ||||
|           '" data-media-url-hd="' + | ||||
|           m.url + | ||||
|           '" data-media-alt-txt="' + | ||||
|           (m.description ? this.#escapeHTML(m.description) : "") + | ||||
|           '" data-media-width-hd="' + | ||||
|           m.meta.original.width + | ||||
|           '" data-media-height-hd="' + | ||||
|           m.meta.original.height + | ||||
|           '" style="padding-top: calc(100%/' + | ||||
|           m.meta.small.aspect + | ||||
|           ')">' + | ||||
| @ -881,14 +910,24 @@ export class Init { | ||||
|           '<img src="' + | ||||
|           m.preview_url + | ||||
|           '" alt="' + | ||||
|           (m.description ? this.#escapeHtml(m.description) : "") + | ||||
|           (m.description ? this.#escapeHTML(m.description) : "") + | ||||
|           '" loading="lazy" />' + | ||||
|           '<button class="mt-post-media-play-icon" title="Load video"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 14"><path d="M9.5 7l-9 6.3V.7z"/></svg></button>' + | ||||
|           '<button class="mt-btn-play" title="Load video"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 14"><path d="M9.5 7l-9 6.3V.7z"/></svg></button>' + | ||||
|           "</div>"; | ||||
|       } else { | ||||
|         media = | ||||
|           '<div class="mt-post-media ' + | ||||
|           (spoiler ? "mt-post-media-spoiler " : "") + | ||||
|           '" data-media-type="' + | ||||
|           m.type + | ||||
|           '" data-media-url-hd="' + | ||||
|           m.url + | ||||
|           '" data-media-alt-txt="' + | ||||
|           (m.description ? this.#escapeHTML(m.description) : "") + | ||||
|           '" data-media-width-hd="' + | ||||
|           m.meta.original.width + | ||||
|           '" data-media-width-hd="' + | ||||
|           m.meta.original.height + | ||||
|           '" style="padding-top: calc(100%/' + | ||||
|           m.meta.small.aspect + | ||||
|           ')">' + | ||||
| @ -899,7 +938,7 @@ export class Init { | ||||
|             : "") + | ||||
|           '<video controls src="' + | ||||
|           m.url + | ||||
|           '"></video>' + | ||||
|           '" loop></video>' + | ||||
|           "</div>"; | ||||
|       } | ||||
|     } | ||||
| @ -907,16 +946,234 @@ export class Init { | ||||
|     return media; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Open a dialog/modal with the styles of Mastodon timeline | ||||
|    * @param {string} i Dialog Id name | ||||
|    * @param {string} c Dialog HTML content | ||||
|    */ | ||||
|   #openDialog(i, c) { | ||||
|     let dialog = document.createElement("dialog"); | ||||
|     dialog.id = i; | ||||
|     dialog.classList.add("mt-dialog"); | ||||
|     dialog.dataset.theme = this.mtContainerNode.getAttribute("data-theme"); | ||||
|     dialog.innerHTML = c; | ||||
|     document.body.prepend(dialog); | ||||
|     dialog.showModal(); | ||||
|     dialog.addEventListener("close", () => { | ||||
|       document.body.removeChild(dialog); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Build a carousel/lightbox with the media content in the post clicked | ||||
|    * @param {event} e User interaction trigger | ||||
|    */ | ||||
|   #buildCarousel(e) { | ||||
|     // List all medias in the post and remove sensitive/spoiler medias
 | ||||
|     const mediaSiblings = Array.from( | ||||
|       e.target.parentNode.parentNode.children | ||||
|     ).filter((element) => !element.classList.contains("mt-post-media-spoiler")); | ||||
|     const mediaClickedIndex = mediaSiblings.indexOf(e.target.parentNode) + 1; | ||||
| 
 | ||||
|     // Build media element and wrapper
 | ||||
|     let mediaItems = []; | ||||
|     mediaSiblings.forEach((sibling, i) => { | ||||
|       let mediaElement = ""; | ||||
|       if ( | ||||
|         sibling.getAttribute("data-media-type") === "gifv" || | ||||
|         sibling.getAttribute("data-media-type") === "video" | ||||
|       ) { | ||||
|         mediaElement = ` | ||||
|         <video controls src="${sibling.getAttribute( | ||||
|           "data-media-url-hd" | ||||
|         )}" width="${sibling.getAttribute( | ||||
|           "data-media-width-hd" | ||||
|         )}" height="${sibling.getAttribute( | ||||
|           "data-media-height-hd" | ||||
|         )}" class="mt-carousel-media" style="max-width:${sibling.getAttribute( | ||||
|           "data-media-width-hd" | ||||
|         )}px; max-height:${sibling.getAttribute( | ||||
|           "data-media-height-hd" | ||||
|         )}px" loop> | ||||
|         </video> | ||||
|         `;
 | ||||
|       } else { | ||||
|         mediaElement = ` | ||||
|         <img src="${sibling.getAttribute( | ||||
|           "data-media-url-hd" | ||||
|         )}" width="${sibling.getAttribute( | ||||
|           "data-media-width-hd" | ||||
|         )}" height="${sibling.getAttribute( | ||||
|           "data-media-height-hd" | ||||
|         )}" class="mt-carousel-media mt-loading-spinner" alt="${sibling.getAttribute( | ||||
|           "data-media-alt-txt" | ||||
|         )}" style="max-width:${sibling.getAttribute( | ||||
|           "data-media-width-hd" | ||||
|         )}px; max-height:${sibling.getAttribute( | ||||
|           "data-media-height-hd" | ||||
|         )}px" dragabble="false" /> | ||||
|         `;
 | ||||
|       } | ||||
| 
 | ||||
|       const mediaWrapper = ` | ||||
|       <li class="mt-carousel-item"> | ||||
|         <div id="mt-carousel-${ | ||||
|           i + 1 | ||||
|         }" class="mt-carousel-media-wrapper" data-media-type="${sibling.getAttribute( | ||||
|         "data-media-type" | ||||
|       )}"> | ||||
|           ${mediaElement} | ||||
|         </div> | ||||
|       </li> | ||||
|       `;
 | ||||
| 
 | ||||
|       mediaItems.push(mediaWrapper); | ||||
|     }); | ||||
| 
 | ||||
|     // Build carousel
 | ||||
|     const carouselHTML = ` | ||||
|     <div class="mt-carousel-header"> | ||||
|       <form method="dialog"> | ||||
|         <button id="mt-carousel-close" class="mt-btn-dark" title="${ | ||||
|           this.mtSettings.carouselCloseTxt | ||||
|         }"> | ||||
|           <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none"> | ||||
|             <path fill-rule="evenodd" d="M5.293 5.293a1 1 0 0 1 1.414 0L12 10.586l5.293-5.293a1 1 0 0 1 1.414 1.414L13.414 12l5.293 5.293a1 1 0 0 1-1.414 1.414L12 13.414l-5.293 5.293a1 1 0 0 1-1.414-1.414L10.586 12 5.293 6.707a1 1 0 0 1 0-1.414z" fill="var(--mt-color-content-txt)"/> | ||||
|           </svg> | ||||
|         </button> | ||||
|       </form> | ||||
|     </div> | ||||
| 
 | ||||
|     <div class="mt-carousel-body"> | ||||
|       <ul id="mt-carousel-scroll" class="mt-carousel-scroll"> | ||||
|         ${mediaItems.join("")} | ||||
|       </ul> | ||||
|     </div> | ||||
| 
 | ||||
|     <button id="mt-carousel-prev" class="mt-carousel-prev" title="${ | ||||
|       this.mtSettings.carouselPrevTxt | ||||
|     }" ${mediaClickedIndex === 1 ? "hidden" : ""}> | ||||
|       <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24" aria-hidden="true"> | ||||
|         <path d="M560-240 320-480l240-240 56 56-184 184 184 184-56 56Z" fill="var(--mt-color-content-txt)"></path> | ||||
|       </svg> | ||||
|     </button> | ||||
| 
 | ||||
|     <button id="mt-carousel-next" class="mt-carousel-next" title="${ | ||||
|       this.mtSettings.carouselNextTxt | ||||
|     }" ${mediaClickedIndex === mediaSiblings.length ? "hidden" : ""}> | ||||
|       <svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24" aria-hidden="true"> | ||||
|         <path d="M504-480 320-664l56-56 240 240-240 240-56-56 184-184Z" fill="var(--mt-color-content-txt)"></path> | ||||
|       </svg> | ||||
|     </button> | ||||
|   `;
 | ||||
| 
 | ||||
|     // Call dialog/modal with carousel "id" and HTML content
 | ||||
|     this.#openDialog("mt-carousel", carouselHTML); | ||||
| 
 | ||||
|     // Set carousel interactions for horizontal scroll and buttons
 | ||||
|     if (mediaItems.length >= 2) { | ||||
|       this.#setCarouselInteractions(mediaSiblings.length, mediaClickedIndex); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Add interactions for the carousel | ||||
|    * @param {number} t Total number of medias loaded | ||||
|    * @param {number} m Index position of media clicked by user | ||||
|    */ | ||||
|   #setCarouselInteractions(t, m) { | ||||
|     let currentMediaIndex = m; | ||||
|     const carousel = document.getElementById("mt-carousel-scroll"); | ||||
|     let scrollTimeout = 0; | ||||
|     let userScrolling = false; | ||||
|     const prevBtn = document.getElementById("mt-carousel-prev"); | ||||
|     const nextBtn = document.getElementById("mt-carousel-next"); | ||||
| 
 | ||||
|     // Scroll the carusel to the media element
 | ||||
|     const scrollCarouselTo = (i, behavior = "smooth") => { | ||||
|       document | ||||
|         .getElementById("mt-carousel-" + i) | ||||
|         .scrollIntoView({ behavior: behavior }); | ||||
|     }; | ||||
|     // First run, place the scroll on clicked media
 | ||||
|     scrollCarouselTo(currentMediaIndex, "instant"); | ||||
| 
 | ||||
|     // Get current index of the media shown on screen
 | ||||
|     const updateMediaIndex = () => { | ||||
|       const scrolledMedia = | ||||
|         (carousel.scrollLeft + carousel.clientWidth) / carousel.clientWidth; | ||||
|       return Math.round(scrolledMedia + Number.EPSILON); | ||||
|     }; | ||||
| 
 | ||||
|     // Scroll interactions
 | ||||
|     const isScrolling = () => { | ||||
|       clearTimeout(scrollTimeout); | ||||
|       scrollTimeout = setTimeout(() => { | ||||
|         if (userScrolling) { | ||||
|           currentMediaIndex = updateMediaIndex(); | ||||
|           checkBtnsVisibility(); | ||||
|         } | ||||
|         userScrolling = true; | ||||
|       }, 60); | ||||
|     }; | ||||
|     carousel.addEventListener("scroll", isScrolling); | ||||
| 
 | ||||
|     // Click interactions
 | ||||
|     const checkBtnsVisibility = () => { | ||||
|       prevBtn.hidden = currentMediaIndex === 1; | ||||
|       nextBtn.hidden = currentMediaIndex === t; | ||||
|     }; | ||||
| 
 | ||||
|     const userClick = (e) => { | ||||
|       const idTarget = e.target.closest("button")?.id; | ||||
| 
 | ||||
|       // Prev/next buttons
 | ||||
|       if (idTarget === "mt-carousel-next") { | ||||
|         userScrolling = false; | ||||
|         ++currentMediaIndex; | ||||
|         if (currentMediaIndex > t) currentMediaIndex = t; | ||||
|         scrollCarouselTo(currentMediaIndex); | ||||
|         checkBtnsVisibility(); | ||||
|       } else if (idTarget === "mt-carousel-prev") { | ||||
|         userScrolling = false; | ||||
|         --currentMediaIndex; | ||||
|         if (currentMediaIndex < 1) currentMediaIndex = 1; | ||||
|         scrollCarouselTo(currentMediaIndex); | ||||
|         checkBtnsVisibility(); | ||||
|       } | ||||
| 
 | ||||
|       // Close button
 | ||||
|       if (idTarget === "mt-carousel-close") { | ||||
|         killEventListeners(); | ||||
|       } | ||||
|     }; | ||||
|     document.addEventListener("click", userClick); | ||||
| 
 | ||||
|     // Keyboard interactions
 | ||||
|     const userKeyDown = (e) => { | ||||
|       if (e.key === "Escape" || e.keyCode === 27) { | ||||
|         killEventListeners(); | ||||
|       } | ||||
|     }; | ||||
|     document.addEventListener("keydown", userKeyDown); | ||||
| 
 | ||||
|     // Kill carousel listeners
 | ||||
|     const killEventListeners = () => { | ||||
|       carousel.removeEventListener("scroll", isScrolling); | ||||
|       document.removeEventListener("click", userClick); | ||||
|       document.removeEventListener("keydown", userKeyDown); | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Replace the video preview image by the video player | ||||
|    * @param {event} e User interaction trigger | ||||
|    */ | ||||
|   #loadPostVideo(e) { | ||||
|     const parentNode = e.target.closest("[data-video-url]"); | ||||
|     const videoUrl = parentNode.dataset.videoUrl; | ||||
|     const parentNode = e.target.closest("[data-media-type]"); | ||||
|     const urlVideo = parentNode.dataset.mediaUrlHd; | ||||
|     parentNode.replaceChildren(); | ||||
|     parentNode.innerHTML = | ||||
|       '<video controls src="' + videoUrl + '" autoplay></video>'; | ||||
|     parentNode.innerHTML = `<video controls src="${urlVideo}" autoplay loop></video>`; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
| @ -924,28 +1181,29 @@ export class Init { | ||||
|    * @param {event} e User interaction trigger | ||||
|    */ | ||||
|   #toogleSpoiler(e) { | ||||
|     const nextSibling = e.target.nextSibling; | ||||
|     const target = e.target; | ||||
|     const nextSibling = target.nextSibling; | ||||
|     if ( | ||||
|       nextSibling.localName === "img" || | ||||
|       nextSibling.localName === "audio" || | ||||
|       nextSibling.localName === "video" | ||||
|     ) { | ||||
|       e.target.parentNode.classList.remove("mt-post-media-spoiler"); | ||||
|       e.target.style.display = "none"; | ||||
|       target.parentNode.classList.remove("mt-post-media-spoiler"); | ||||
|       target.style.display = "none"; | ||||
|     } else if ( | ||||
|       nextSibling.classList.contains("spoiler-txt-hidden") || | ||||
|       nextSibling.classList.contains("spoiler-txt-visible") | ||||
|     ) { | ||||
|       if (e.target.textContent == this.mtSettings.btnShowMore) { | ||||
|       if (target.textContent == this.mtSettings.btnShowMore) { | ||||
|         nextSibling.classList.remove("spoiler-txt-hidden"); | ||||
|         nextSibling.classList.add("spoiler-txt-visible"); | ||||
|         e.target.setAttribute("aria-expanded", "true"); | ||||
|         e.target.textContent = this.mtSettings.btnShowLess; | ||||
|         target.setAttribute("aria-expanded", "true"); | ||||
|         target.textContent = this.mtSettings.btnShowLess; | ||||
|       } else { | ||||
|         nextSibling.classList.remove("spoiler-txt-visible"); | ||||
|         nextSibling.classList.add("spoiler-txt-hidden"); | ||||
|         e.target.setAttribute("aria-expanded", "false"); | ||||
|         e.target.textContent = this.mtSettings.btnShowMore; | ||||
|         target.setAttribute("aria-expanded", "false"); | ||||
|         target.textContent = this.mtSettings.btnShowMore; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| @ -966,7 +1224,7 @@ export class Init { | ||||
|           '"><img src="' + | ||||
|           c.image + | ||||
|           '" alt="' + | ||||
|           this.#escapeHtml(c.image_description) + | ||||
|           this.#escapeHTML(c.image_description) + | ||||
|           '" loading="lazy" /></div>' | ||||
|         : '<div class="mt-post-preview-noImage">📄</div>') + | ||||
|       "</div>" + | ||||
| @ -1032,25 +1290,26 @@ export class Init { | ||||
|         } else if (this.mtSettings.timelineType === "local") { | ||||
|           btnSeeMorePath = "public/local"; | ||||
|         } | ||||
|         const btnSeeMoreHTML = | ||||
|           '<a class="mt-btn-violet btn-see-more" href="' + | ||||
|           this.mtSettings.instanceUrl + | ||||
|           "/" + | ||||
|           this.#escapeHtml(btnSeeMorePath) + | ||||
|           '" rel="nofollow noopener noreferrer" target="_blank">' + | ||||
|           this.mtSettings.btnSeeMore + | ||||
|           "</a>"; | ||||
|         const btnSeeMoreHTML = ` | ||||
|           <a class="mt-btn-violet btn-see-more" href="${ | ||||
|             this.mtSettings.instanceUrl | ||||
|           }/${this.#escapeHTML( | ||||
|           btnSeeMorePath | ||||
|         )}" rel="nofollow noopener noreferrer" target="_blank"> | ||||
|             ${this.mtSettings.btnSeeMore} | ||||
|           </a>`; | ||||
| 
 | ||||
|         containerFooter.insertAdjacentHTML("beforeend", btnSeeMoreHTML); | ||||
|       } | ||||
| 
 | ||||
|       // Create button to refresh the timeline
 | ||||
|       if (this.mtSettings.btnReload) { | ||||
|         const btnReloadHTML = | ||||
|           '<button class="mt-btn-violet btn-refresh">' + | ||||
|           '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none"><path d="M21 3v5m0 0h-5m5 0l-3-2.708C16.408 3.867 14.305 3 12 3a9 9 0 1 0 0 18c4.283 0 7.868-2.992 8.777-7" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>' + | ||||
|           this.mtSettings.btnReload + | ||||
|           "</button>"; | ||||
|         const btnReloadHTML = ` | ||||
|           <button class="mt-btn-violet btn-refresh"> | ||||
|             <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none"><path d="M21 3v5m0 0h-5m5 0l-3-2.708C16.408 3.867 14.305 3 12 3a9 9 0 1 0 0 18c4.283 0 7.868-2.992 8.777-7" stroke="var(--mt-color-btn-txt)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | ||||
|             </svg> | ||||
|               ${this.mtSettings.btnReload} | ||||
|           </button>`; | ||||
| 
 | ||||
|         containerFooter.insertAdjacentHTML("beforeend", btnReloadHTML); | ||||
| 
 | ||||
| @ -1068,39 +1327,57 @@ export class Init { | ||||
|    */ | ||||
|   #setPostsInteracion() { | ||||
|     this.mtBodyNode.addEventListener("click", (e) => { | ||||
|       const target = e.target; | ||||
|       const localName = target.localName; | ||||
|       const parentNode = target.parentNode; | ||||
| 
 | ||||
|       // Check if post cointainer was clicked
 | ||||
|       if ( | ||||
|         e.target.localName == "article" || | ||||
|         e.target.offsetParent?.localName == "article" || | ||||
|         (e.target.localName == "img" && | ||||
|           !e.target.parentNode.getAttribute("data-video-url")) | ||||
|         localName == "article" || | ||||
|         target.offsetParent?.localName == "article" || | ||||
|         (localName == "img" && | ||||
|           this.mtSettings.disableCarousel && | ||||
|           parentNode.getAttribute("data-media-type") !== "video" && | ||||
|           parentNode.getAttribute("data-media-type") !== "gifv") | ||||
|       ) { | ||||
|         this.#openPostUrl(e); | ||||
|       } | ||||
| 
 | ||||
|       // Check if Show More/Less button was clicked
 | ||||
|       if ( | ||||
|         e.target.localName == "button" && | ||||
|         e.target.classList.contains("mt-btn-spoiler") | ||||
|         localName == "button" && | ||||
|         target.classList.contains("mt-btn-spoiler") | ||||
|       ) { | ||||
|         this.#toogleSpoiler(e); | ||||
|       } | ||||
| 
 | ||||
|       // Check if image in post was clicked
 | ||||
|       if ( | ||||
|         localName == "img" && | ||||
|         !this.mtSettings.disableCarousel && | ||||
|         parentNode.getAttribute("data-media-type") !== "video" && | ||||
|         parentNode.getAttribute("data-media-type") !== "gifv" | ||||
|       ) { | ||||
|         this.#buildCarousel(e); | ||||
|       } | ||||
| 
 | ||||
|       // Check if video preview image or play icon/button was clicked
 | ||||
|       if ( | ||||
|         e.target.className == "mt-post-media-play-icon" || | ||||
|         (e.target.localName == "svg" && | ||||
|           e.target.parentNode.className == "mt-post-media-play-icon") || | ||||
|         (e.target.localName == "path" && | ||||
|           e.target.parentNode.parentNode.className == | ||||
|             "mt-post-media-play-icon") || | ||||
|         (e.target.localName == "img" && | ||||
|           e.target.parentNode.getAttribute("data-video-url")) | ||||
|         target.className == "mt-btn-play" || | ||||
|         (localName == "svg" && parentNode.className == "mt-btn-play") || | ||||
|         (localName == "path" && | ||||
|           parentNode.parentNode.className == "mt-btn-play") || | ||||
|         (localName == "img" && | ||||
|           (parentNode.getAttribute("data-media-type") === "video" || | ||||
|             parentNode.getAttribute("data-media-type") === "gifv")) | ||||
|       ) { | ||||
|         this.#loadPostVideo(e); | ||||
|       } | ||||
|     }); | ||||
|     this.mtBodyNode.addEventListener("keydown", (e) => { | ||||
|       const localName = e.target.localName; | ||||
|       // Check if Enter key was pressed with focus in an article
 | ||||
|       if (e.key === "Enter" && e.target.localName == "article") { | ||||
|       if (e.key === "Enter" && localName == "article") { | ||||
|         this.#openPostUrl(e); | ||||
|       } | ||||
|     }); | ||||
| @ -1118,6 +1395,7 @@ export class Init { | ||||
|       e.target.localName !== "button" && | ||||
|       e.target.localName !== "bdi" && | ||||
|       e.target.localName !== "time" && | ||||
|       !e.target.classList.contains("mt-post-media-spoiler") && | ||||
|       e.target.className !== "mt-post-preview-noImage" && | ||||
|       e.target.parentNode.className !== "mt-post-avatar-image-big" && | ||||
|       e.target.parentNode.className !== "mt-post-avatar-image-small" && | ||||
| @ -1155,12 +1433,12 @@ export class Init { | ||||
|    */ | ||||
|   #showError(t, i) { | ||||
|     const icon = i || "❌"; | ||||
|     this.mtBodyNode.innerHTML = | ||||
|       '<div class="mt-error"><span class="mt-error-icon">' + | ||||
|       icon + | ||||
|       '</span><br/><strong>Oops, something\'s happened:</strong><br/><div class="mt-error-message">' + | ||||
|       t + | ||||
|       "</div></div>"; | ||||
|     this.mtBodyNode.innerHTML = ` | ||||
|       <div class="mt-error"> | ||||
|         <span class="mt-error-icon">${icon}</span> | ||||
|         <strong>Oops, something's happened:</strong> | ||||
|         <div class="mt-error-message">${t}</div> | ||||
|       </div>`; | ||||
|     this.mtBodyNode.setAttribute("role", "none"); | ||||
|     throw new Error( | ||||
|       "Stopping the script due to an error building the timeline." | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 i.j
						i.j