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 | v4.3.3 - 01/03/2024 | ||||||
| - Fix click conflict on user name | - Fix click conflict on user name | ||||||
| - Render emojos in user name | - Render emojos in user name | ||||||
| @ -58,7 +64,7 @@ v3.13.1 - 12/01/2024 | |||||||
| v3.12.0 - 11/12/2023 | v3.12.0 - 11/12/2023 | ||||||
| - Fix link preview event on click | - Fix link preview event on click | ||||||
| 
 | 
 | ||||||
| v3.11.0 - 4/11/2023 | v3.11.0 - 04/11/2023 | ||||||
| - Update icons | - Update icons | ||||||
| - Improve loader spinner | - Improve loader spinner | ||||||
| 
 | 
 | ||||||
| @ -103,7 +109,7 @@ v3.8.1 - 14/08/2023 | |||||||
| - Improve JS comments | - Improve JS comments | ||||||
| 
 | 
 | ||||||
| v3.8.0 - 04/08/2023 | 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 | v3.7.2 - 25/07/2023 | ||||||
| - Use window.onload to take async attribute into account | - 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: | Demo running: | ||||||
| <https://codepen.io/ipuntoj/pen/MWppNGL> | <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: | Copy the following CSS and JS links to include them in your project: | ||||||
| 
 | 
 | ||||||
| ```html | ```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 | ```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 | ### Package manager | ||||||
| @ -108,7 +108,7 @@ To get your timeline up add the following HTML structure in your page: | |||||||
| </div> | </div> | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| Then after that you can initialize the script by running: | Now you can then initialize the script running: | ||||||
| 
 | 
 | ||||||
| ```js | ```js | ||||||
| const myTimeline = new MastodonTimeline.Init(); | 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 |   // Default: don't hide | ||||||
|   hidePinnedPosts: false, |   hidePinnedPosts: false, | ||||||
| 
 | 
 | ||||||
|   // Hide user account under the user name |   // Hide the user account under the user name | ||||||
|   // Default: don't hide |   // Default: don't hide | ||||||
|   hideUserAccount: false, |   hideUserAccount: false, | ||||||
| 
 | 
 | ||||||
| @ -270,15 +270,24 @@ Here you have all the options available to quickly setup and customize your time | |||||||
|   // Default: don't apply |   // Default: don't apply | ||||||
|   markdownBlockquote: false, |   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 |   // Limit the text content to a maximum number of lines | ||||||
|   // Default: 0 (unlimited) |   // Default: 0 (unlimited) | ||||||
|   txtMaxLines: "0", |   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", |   btnShowMore: "SHOW MORE", | ||||||
|   btnShowLess: "SHOW LESS", |   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", |   btnShowContent: "SHOW CONTENT", | ||||||
| 
 | 
 | ||||||
|   // Customize the text of the button pointing to the Mastodon page placed at the end of the timeline |   // 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; |         margin: 2rem 0; | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       /* Customized CSS styles */ |       /* Example of customized CSS styles */ | ||||||
|       .mt-container { |       .mt-container { | ||||||
|  |         font-family: monospace; | ||||||
|         background-color: transparent; |         background-color: transparent; | ||||||
|         border: 1px solid white; |         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, | ||||||
|       .mt-container a:active, |       .mt-container a:active, | ||||||
|       .mt-container a:link { |       .mt-container a:link { | ||||||
|         color: darkgreen; |         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> |     </style> | ||||||
|   </head> |   </head> | ||||||
| 
 | 
 | ||||||
| @ -105,8 +123,7 @@ | |||||||
|         <p> |         <p> | ||||||
|           At JS level, it defaults to the light theme and the date is displayed |           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 |           in US format using digits only. In order to achieve a minimalist | ||||||
|           style, the following options have been changed at its |           style, the following options have been changed at its initialization: | ||||||
|           initialization: |  | ||||||
|         </p> |         </p> | ||||||
|         <pre> |         <pre> | ||||||
|         <code> |         <code> | ||||||
|  | |||||||
							
								
								
									
										189
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										189
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -1,12 +1,12 @@ | |||||||
| { | { | ||||||
|   "name": "@idotj/mastodon-embed-timeline", |   "name": "@idotj/mastodon-embed-timeline", | ||||||
|   "version": "4.3.3", |   "version": "4.3.5", | ||||||
|   "lockfileVersion": 3, |   "lockfileVersion": 3, | ||||||
|   "requires": true, |   "requires": true, | ||||||
|   "packages": { |   "packages": { | ||||||
|     "": { |     "": { | ||||||
|       "name": "@idotj/mastodon-embed-timeline", |       "name": "@idotj/mastodon-embed-timeline", | ||||||
|       "version": "4.3.3", |       "version": "4.3.5", | ||||||
|       "license": "GNU", |       "license": "GNU", | ||||||
|       "devDependencies": { |       "devDependencies": { | ||||||
|         "@rollup/plugin-terser": "^0.4.4", |         "@rollup/plugin-terser": "^0.4.4", | ||||||
| @ -15,14 +15,14 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@jridgewell/gen-mapping": { |     "node_modules/@jridgewell/gen-mapping": { | ||||||
|       "version": "0.3.3", |       "version": "0.3.5", | ||||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", |       "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", | ||||||
|       "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", |       "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@jridgewell/set-array": "^1.0.1", |         "@jridgewell/set-array": "^1.2.1", | ||||||
|         "@jridgewell/sourcemap-codec": "^1.4.10", |         "@jridgewell/sourcemap-codec": "^1.4.10", | ||||||
|         "@jridgewell/trace-mapping": "^0.3.9" |         "@jridgewell/trace-mapping": "^0.3.24" | ||||||
|       }, |       }, | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=6.0.0" |         "node": ">=6.0.0" | ||||||
| @ -38,9 +38,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/@jridgewell/set-array": { |     "node_modules/@jridgewell/set-array": { | ||||||
|       "version": "1.1.2", |       "version": "1.2.1", | ||||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", |       "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", | ||||||
|       "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", |       "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=6.0.0" |         "node": ">=6.0.0" | ||||||
| @ -63,9 +63,9 @@ | |||||||
|       "dev": true |       "dev": true | ||||||
|     }, |     }, | ||||||
|     "node_modules/@jridgewell/trace-mapping": { |     "node_modules/@jridgewell/trace-mapping": { | ||||||
|       "version": "0.3.22", |       "version": "0.3.24", | ||||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", |       "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.24.tgz", | ||||||
|       "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", |       "integrity": "sha512-+VaWXDa6+l6MhflBvVXjIEAzb59nQ2JUK3bwRp2zRpPtU+8TFRy9Gg/5oIcNlkEL5PGlBFGfemUVvIgLnTzq7Q==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@jridgewell/resolve-uri": "^3.1.0", |         "@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": { |     "node_modules/@rollup/rollup-linux-x64-gnu": { | ||||||
|       "version": "4.12.0", |       "version": "4.12.0", | ||||||
|       "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.12.0.tgz", |       "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.12.0.tgz", | ||||||
| @ -120,6 +224,45 @@ | |||||||
|         "linux" |         "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": { |     "node_modules/@types/estree": { | ||||||
|       "version": "1.0.5", |       "version": "1.0.5", | ||||||
|       "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", |       "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", | ||||||
| @ -281,6 +424,20 @@ | |||||||
|       "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", |       "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", | ||||||
|       "dev": true |       "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": { |     "node_modules/glob": { | ||||||
|       "version": "7.2.3", |       "version": "7.2.3", | ||||||
|       "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", |       "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", | ||||||
| @ -530,9 +687,9 @@ | |||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "node_modules/terser": { |     "node_modules/terser": { | ||||||
|       "version": "5.27.1", |       "version": "5.28.1", | ||||||
|       "resolved": "https://registry.npmjs.org/terser/-/terser-5.27.1.tgz", |       "resolved": "https://registry.npmjs.org/terser/-/terser-5.28.1.tgz", | ||||||
|       "integrity": "sha512-29wAr6UU/oQpnTw5HoadwjUZnFQXGdOfj0LjZ4sVxzqwHh/QVkvr7m8y9WoR4iN3FRitVduTc6KdjcW38Npsug==", |       "integrity": "sha512-wM+bZp54v/E9eRRGXb5ZFDvinrJIOaTapx3WUokyVGZu5ucVCK55zEgGd5Dl2fSr3jUo5sDiERErUWLY6QPFyA==", | ||||||
|       "dev": true, |       "dev": true, | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@jridgewell/source-map": "^0.3.3", |         "@jridgewell/source-map": "^0.3.3", | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "@idotj/mastodon-embed-timeline", |   "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.", |   "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", |   "license": "GNU", | ||||||
|   "author": { |   "author": { | ||||||
|  | |||||||
| @ -1,10 +1,12 @@ | |||||||
| /* Mastodon embed timeline v4.3.3 */ | /* Mastodon embed timeline v4.3.5 */ | ||||||
| /* More info at: */ | /* More info at: */ | ||||||
| /* https://gitlab.com/idotj/mastodon-embed-timeline */ | /* https://gitlab.com/idotj/mastodon-embed-timeline */ | ||||||
| 
 | 
 | ||||||
| /* Variables */ | /* Variables */ | ||||||
| .mt-container, | .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-txt-max-lines: none; | ||||||
|   --mt-color-bg: #fff; |   --mt-color-bg: #fff; | ||||||
|   --mt-color-bg-hover: #d9e1e8; |   --mt-color-bg-hover: #d9e1e8; | ||||||
| @ -16,8 +18,10 @@ | |||||||
|   --mt-color-btn-bg: #6364ff; |   --mt-color-btn-bg: #6364ff; | ||||||
|   --mt-color-btn-bg-hover: #563acc; |   --mt-color-btn-bg-hover: #563acc; | ||||||
|   --mt-color-btn-txt: #fff; |   --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: #282c37; | ||||||
|   --mt-color-bg-hover: #313543; |   --mt-color-bg-hover: #313543; | ||||||
|   --mt-color-line-gray: #393f4f; |   --mt-color-line-gray: #393f4f; | ||||||
| @ -28,11 +32,13 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Reset CSS */ | /* Reset CSS */ | ||||||
| .mt-container button { | .mt-container button, | ||||||
|  | .mt-dialog button { | ||||||
|   font: inherit; |   font: inherit; | ||||||
| } | } | ||||||
| .mt-container a, | .mt-container a, | ||||||
| .mt-container button { | .mt-container button, | ||||||
|  | .mt-dialog button { | ||||||
|   cursor: pointer; |   cursor: pointer; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -254,18 +260,30 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Medias */ | /* Medias */ | ||||||
|  | .mt-post-media-wrapper { | ||||||
|  |   display: flex; | ||||||
|  |   flex-direction: column; | ||||||
|  |   gap: 1rem; | ||||||
|  |   margin-bottom: 1rem; | ||||||
|  | } | ||||||
| .mt-post-media { | .mt-post-media { | ||||||
|   position: relative; |   position: relative; | ||||||
|   overflow: hidden; |   overflow: hidden; | ||||||
|   margin-bottom: 1rem; |  | ||||||
| } | } | ||||||
| .mt-post-media-spoiler > img, | .mt-post-media-spoiler > img, | ||||||
| .mt-post-media-spoiler > audio, | .mt-post-media-spoiler > audio, | ||||||
| .mt-post-media-spoiler > video, | .mt-post-media-spoiler > video, | ||||||
| .mt-post-media-spoiler > .mt-post-media-play-icon { | .mt-post-media-spoiler > .mt-btn-play { | ||||||
|   filter: blur(2rem); |   filter: blur(2rem); | ||||||
|   pointer-events: none; |   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 { | .mt-post-media > audio { | ||||||
|   width: 100%; |   width: 100%; | ||||||
|   position: relative; |   position: relative; | ||||||
| @ -282,28 +300,93 @@ | |||||||
|   text-align: center; |   text-align: center; | ||||||
|   color: var(--mt-color-content-txt); |   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; |   display: flex; | ||||||
|   position: absolute; |   flex-direction: column; | ||||||
|   width: 3rem; |  | ||||||
|   height: 3rem; |  | ||||||
|   top: calc(50% - 1.5rem); |  | ||||||
|   left: calc(50% - 1.5rem); |  | ||||||
|   justify-content: center; |  | ||||||
|   align-items: center; |   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; |   background-color: transparent; | ||||||
|   border: none; |   border: none; | ||||||
|   cursor: pointer; |   padding: 0.5rem; | ||||||
|  |   z-index: 2; | ||||||
| } | } | ||||||
| .mt-post-media-play-icon > svg { | .mt-carousel-prev { | ||||||
|   width: 2.5rem; |   left: 0; | ||||||
|   height: 2.5rem; |   padding-left: 0; | ||||||
|   fill: var(--mt-color-bg); | } | ||||||
|   stroke: var(--mt-color-content-txt); | .mt-carousel-next { | ||||||
|   stroke-width: 1px; |   right: 0; | ||||||
|  |   padding-right: 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Preview link */ | /* Preview link */ | ||||||
| @ -372,7 +455,31 @@ | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Buttons */ | /* 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; |   display: flex; | ||||||
|   border-radius: 0.25rem; |   border-radius: 0.25rem; | ||||||
|   background-color: var(--mt-color-line-gray); |   background-color: var(--mt-color-line-gray); | ||||||
| @ -381,11 +488,15 @@ | |||||||
|   font-weight: 600; |   font-weight: 600; | ||||||
|   font-size: 0.75rem; |   font-size: 0.75rem; | ||||||
|   text-align: center; |   text-align: center; | ||||||
|   padding: 0 0.5rem; |   padding: 0.25rem 0.5rem; | ||||||
|   line-height: 1.25rem; |   line-height: 1.25rem; | ||||||
| 
 |  | ||||||
|   vertical-align: top; |   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 .mt-btn-violet, | ||||||
| .mt-container a.mt-btn-violet { | .mt-container a.mt-btn-violet { | ||||||
|   display: flex; |   display: flex; | ||||||
| @ -400,6 +511,8 @@ | |||||||
|   background-color: var(--mt-color-btn-bg); |   background-color: var(--mt-color-btn-bg); | ||||||
|   color: var(--mt-color-btn-txt); |   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 .mt-btn-violet:hover, | ||||||
| .mt-container a.mt-btn-violet:hover { | .mt-container a.mt-btn-violet:hover { | ||||||
|   background-color: var(--mt-color-btn-bg-hover); |   background-color: var(--mt-color-btn-bg-hover); | ||||||
| @ -407,6 +520,7 @@ | |||||||
| } | } | ||||||
| .mt-post-txt .mt-btn-spoiler { | .mt-post-txt .mt-btn-spoiler { | ||||||
|   display: inline-block; |   display: inline-block; | ||||||
|  |   vertical-align: middle; | ||||||
| } | } | ||||||
| .mt-post-media.mt-loading-spinner > .mt-btn-spoiler { | .mt-post-media.mt-loading-spinner > .mt-btn-spoiler { | ||||||
|   display: none; |   display: none; | ||||||
| @ -436,6 +550,7 @@ | |||||||
| } | } | ||||||
| .mt-error-icon { | .mt-error-icon { | ||||||
|   font-size: 2rem; |   font-size: 2rem; | ||||||
|  |   margin-bottom: 1rem; | ||||||
| } | } | ||||||
| .mt-error-message { | .mt-error-message { | ||||||
|   width: 100%; |   width: 100%; | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| /** | /** | ||||||
|  * Mastodon embed timeline |  * Mastodon embed timeline | ||||||
|  * @author idotj |  * @author idotj | ||||||
|  * @version 4.3.3 |  * @version 4.3.5 | ||||||
|  * @url https://gitlab.com/idotj/mastodon-embed-timeline
 |  * @url https://gitlab.com/idotj/mastodon-embed-timeline
 | ||||||
|  * @license GNU AGPLv3 |  * @license GNU AGPLv3 | ||||||
|  */ |  */ | ||||||
| @ -36,6 +36,10 @@ export class Init { | |||||||
|       hidePreviewLink: false, |       hidePreviewLink: false, | ||||||
|       hideCounterBar: false, |       hideCounterBar: false, | ||||||
|       markdownBlockquote: false, |       markdownBlockquote: false, | ||||||
|  |       disableCarousel: false, | ||||||
|  |       carouselCloseTxt: "Close carousel", | ||||||
|  |       carouselPrevTxt: "Previous media item", | ||||||
|  |       carouselNextTxt: "Next media item", | ||||||
|       txtMaxLines: "0", |       txtMaxLines: "0", | ||||||
|       btnShowMore: "SHOW MORE", |       btnShowMore: "SHOW MORE", | ||||||
|       btnShowLess: "SHOW LESS", |       btnShowLess: "SHOW LESS", | ||||||
| @ -172,42 +176,17 @@ export class Init { | |||||||
|    * Requests to the server to collect all the data |    * Requests to the server to collect all the data | ||||||
|    * @returns {object} Data container |    * @returns {object} Data container | ||||||
|    */ |    */ | ||||||
|   #fetchTimelineData() { |   #getTimelineData() { | ||||||
|     return new Promise((resolve, reject) => { |     return new Promise((resolve, reject) => { | ||||||
|       /** |       const instanceApiUrl = `${this.mtSettings.instanceUrl}/api/v1/`; | ||||||
|        * 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
 |  | ||||||
|       let urls = {}; |       let urls = {}; | ||||||
| 
 | 
 | ||||||
|       if (this.mtSettings.instanceUrl) { |       if (this.mtSettings.instanceUrl) { | ||||||
|         if (this.mtSettings.timelineType === "profile") { |         if (this.mtSettings.timelineType === "profile") { | ||||||
|           if (this.mtSettings.userId) { |           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) { |             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 { |           } else { | ||||||
|             this.#showError( |             this.#showError( | ||||||
| @ -217,7 +196,7 @@ export class Init { | |||||||
|           } |           } | ||||||
|         } else if (this.mtSettings.timelineType === "hashtag") { |         } else if (this.mtSettings.timelineType === "hashtag") { | ||||||
|           if (this.mtSettings.hashtagName) { |           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 { |           } else { | ||||||
|             this.#showError( |             this.#showError( | ||||||
|               "Please check your <strong>hashtagName</strong> value", |               "Please check your <strong>hashtagName</strong> value", | ||||||
| @ -225,7 +204,7 @@ export class Init { | |||||||
|             ); |             ); | ||||||
|           } |           } | ||||||
|         } else if (this.mtSettings.timelineType === "local") { |         } 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 { |         } else { | ||||||
|           this.#showError( |           this.#showError( | ||||||
|             "Please check your <strong>timelineType</strong> value", |             "Please check your <strong>timelineType</strong> value", | ||||||
| @ -239,15 +218,15 @@ export class Init { | |||||||
|         ); |         ); | ||||||
|       } |       } | ||||||
|       if (!this.mtSettings.hideEmojos) { |       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]) => { |       const urlsPromises = Object.entries(urls).map(([key, url]) => { | ||||||
|         return fetchData(url) |         return this.#fetchData(url) | ||||||
|           .then((data) => ({ [key]: data })) |           .then((data) => ({ [key]: data })) | ||||||
|           .catch((error) => { |           .catch((error) => { | ||||||
|             reject( |             reject( | ||||||
|               new Error("Something went wrong fetching data from: " + url) |               new Error(`Something went wrong fetching data from: ${url}`) | ||||||
|             ); |             ); | ||||||
|             this.#showError(error.message); |             this.#showError(error.message); | ||||||
|             return { [key]: [] }; |             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 |    * Filter all fetched posts and append them on the timeline | ||||||
|    * @param {string} t Type of build (new or reload) |    * @param {string} t Type of build (new or reload) | ||||||
|    */ |    */ | ||||||
|   async #buildTimeline(t) { |   async #buildTimeline(t) { | ||||||
|     await this.#fetchTimelineData(); |     await this.#getTimelineData(); | ||||||
| 
 | 
 | ||||||
|     // Merge pinned posts with timeline posts
 |     // Merge pinned posts with timeline posts
 | ||||||
|     let posts; |     let posts; | ||||||
| @ -320,10 +317,9 @@ export class Init { | |||||||
| 
 | 
 | ||||||
|     // If there are no posts to display, show an error message
 |     // If there are no posts to display, show an error message
 | ||||||
|     if (this.mtBodyNode.innerHTML === "") { |     if (this.mtBodyNode.innerHTML === "") { | ||||||
|       const errorMessage = |       const errorMessage = `No posts to show<hr/>${ | ||||||
|         "No posts to show <hr/>" + |         posts?.length || 0 | ||||||
|         (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)`;
 | ||||||
|         " 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)"; |  | ||||||
|       this.#showError(errorMessage, "📭"); |       this.#showError(errorMessage, "📭"); | ||||||
|     } else { |     } else { | ||||||
|       if (t === "newTimeline") { |       if (t === "newTimeline") { | ||||||
| @ -379,14 +375,14 @@ export class Init { | |||||||
|         '<img src="' + |         '<img src="' + | ||||||
|         c.reblog.account.avatar + |         c.reblog.account.avatar + | ||||||
|         '" alt="' + |         '" alt="' + | ||||||
|         this.#escapeHtml(c.reblog.account.username) + |         this.#escapeHTML(c.reblog.account.username) + | ||||||
|         ' avatar" loading="lazy" />' + |         ' avatar" loading="lazy" />' + | ||||||
|         "</div>" + |         "</div>" + | ||||||
|         '<div class="mt-post-avatar-image-small">' + |         '<div class="mt-post-avatar-image-small">' + | ||||||
|         '<img src="' + |         '<img src="' + | ||||||
|         c.account.avatar + |         c.account.avatar + | ||||||
|         '" alt="' + |         '" alt="' + | ||||||
|         this.#escapeHtml(c.account.username) + |         this.#escapeHTML(c.account.username) + | ||||||
|         ' avatar" loading="lazy" />' + |         ' avatar" loading="lazy" />' + | ||||||
|         "</div>" + |         "</div>" + | ||||||
|         "</div>" + |         "</div>" + | ||||||
| @ -399,7 +395,9 @@ export class Init { | |||||||
|           c.reblog.account.emojis |           c.reblog.account.emojis | ||||||
|         ); |         ); | ||||||
|       } else { |       } 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) { |       if (!this.mtSettings.hideUserAccount) { | ||||||
| @ -446,7 +444,7 @@ export class Init { | |||||||
|         '<img src="' + |         '<img src="' + | ||||||
|         c.account.avatar + |         c.account.avatar + | ||||||
|         '" alt="' + |         '" alt="' + | ||||||
|         this.#escapeHtml(c.account.username) + |         this.#escapeHTML(c.account.username) + | ||||||
|         ' avatar" loading="lazy" />' + |         ' avatar" loading="lazy" />' + | ||||||
|         "</div>" + |         "</div>" + | ||||||
|         "</div>" + |         "</div>" + | ||||||
| @ -459,7 +457,9 @@ export class Init { | |||||||
|           c.account.emojis |           c.account.emojis | ||||||
|         ); |         ); | ||||||
|       } else { |       } 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) { |       if (!this.mtSettings.hideUserAccount) { | ||||||
| @ -495,22 +495,20 @@ export class Init { | |||||||
| 
 | 
 | ||||||
|     // Date
 |     // Date
 | ||||||
|     formattedDate = this.#formatDate(date); |     formattedDate = this.#formatDate(date); | ||||||
|     const timestamp = |     const timestamp = ` | ||||||
|       '<div class="mt-post-header-date">' + |       <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>' |           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">' + |         <a href="${url}" rel="nofollow noopener noreferrer" target="_blank"> | ||||||
|       '<time datetime="' + |           <time datetime="${date}"> | ||||||
|       date + |             ${formattedDate} | ||||||
|       '">' + |           </time> | ||||||
|       formattedDate + |           ${c.edited_at ? " *" : ""} | ||||||
|       "</time>" + |         </a> | ||||||
|       (c.edited_at ? " *" : "") + |       </div>`; | ||||||
|       "</a>" + |  | ||||||
|       "</div>"; |  | ||||||
| 
 | 
 | ||||||
|     // Main text
 |     // Main text
 | ||||||
|     let txtCss = ""; |     let txtCss = ""; | ||||||
| @ -587,6 +585,7 @@ export class Init { | |||||||
|         ); |         ); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  |     media = `<div class="mt-post-media-wrapper">${media.join("")}</div>`; | ||||||
| 
 | 
 | ||||||
|     // Preview link
 |     // Preview link
 | ||||||
|     let previewLink = ""; |     let previewLink = ""; | ||||||
| @ -655,7 +654,7 @@ export class Init { | |||||||
|       timestamp + |       timestamp + | ||||||
|       "</div>" + |       "</div>" + | ||||||
|       content + |       content + | ||||||
|       media.join("") + |       media + | ||||||
|       previewLink + |       previewLink + | ||||||
|       poll + |       poll + | ||||||
|       counterBar + |       counterBar + | ||||||
| @ -743,7 +742,7 @@ export class Init { | |||||||
|    * @param {string} s String |    * @param {string} s String | ||||||
|    * @returns {string} String |    * @returns {string} String | ||||||
|    */ |    */ | ||||||
|   #escapeHtml(s) { |   #escapeHTML(s) { | ||||||
|     return (s ?? "") |     return (s ?? "") | ||||||
|       .replaceAll("&", "&") |       .replaceAll("&", "&") | ||||||
|       .replaceAll("<", "<") |       .replaceAll("<", "<") | ||||||
| @ -793,7 +792,7 @@ export class Init { | |||||||
|   /** |   /** | ||||||
|    * Create media element |    * Create media element | ||||||
|    * @param {object} m Media content |    * @param {object} m Media content | ||||||
|    * @param {boolean} s Spoiler/Sensitive status |    * @param {boolean} s Sensitive/spoiler status | ||||||
|    * @returns {string} Media in HTML format |    * @returns {string} Media in HTML format | ||||||
|    */ |    */ | ||||||
|   #createMedia(m, s) { |   #createMedia(m, s) { | ||||||
| @ -806,6 +805,16 @@ export class Init { | |||||||
|         '<div class="mt-post-media ' + |         '<div class="mt-post-media ' + | ||||||
|         (spoiler ? "mt-post-media-spoiler " : "") + |         (spoiler ? "mt-post-media-spoiler " : "") + | ||||||
|         this.mtSettings.spinnerClass + |         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%/' + |         '" style="padding-top: calc(100%/' + | ||||||
|         m.meta.small.aspect + |         m.meta.small.aspect + | ||||||
|         ')">' + |         ')">' + | ||||||
| @ -817,7 +826,7 @@ export class Init { | |||||||
|         '<img src="' + |         '<img src="' + | ||||||
|         m.preview_url + |         m.preview_url + | ||||||
|         '" alt="' + |         '" alt="' + | ||||||
|         (m.description ? this.#escapeHtml(m.description) : "") + |         (m.description ? this.#escapeHTML(m.description) : "") + | ||||||
|         '" loading="lazy" />' + |         '" loading="lazy" />' + | ||||||
|         "</div>"; |         "</div>"; | ||||||
|     } |     } | ||||||
| @ -828,6 +837,16 @@ export class Init { | |||||||
|           '<div class="mt-post-media ' + |           '<div class="mt-post-media ' + | ||||||
|           (spoiler ? "mt-post-media-spoiler " : "") + |           (spoiler ? "mt-post-media-spoiler " : "") + | ||||||
|           this.mtSettings.spinnerClass + |           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%/' + |           '" style="padding-top: calc(100%/' + | ||||||
|           m.meta.small.aspect + |           m.meta.small.aspect + | ||||||
|           ')">' + |           ')">' + | ||||||
| @ -842,13 +861,15 @@ export class Init { | |||||||
|           '<img src="' + |           '<img src="' + | ||||||
|           m.preview_url + |           m.preview_url + | ||||||
|           '" alt="' + |           '" alt="' + | ||||||
|           (m.description ? this.#escapeHtml(m.description) : "") + |           (m.description ? this.#escapeHTML(m.description) : "") + | ||||||
|           '" loading="lazy" />' + |           '" loading="lazy" />' + | ||||||
|           "</div>"; |           "</div>"; | ||||||
|       } else { |       } else { | ||||||
|         media = |         media = | ||||||
|           '<div class="mt-post-media ' + |           '<div class="mt-post-media ' + | ||||||
|           (spoiler ? "mt-post-media-spoiler " : "") + |           (spoiler ? "mt-post-media-spoiler " : "") + | ||||||
|  |           '" data-media-type="' + | ||||||
|  |           m.type + | ||||||
|           '">' + |           '">' + | ||||||
|           (spoiler |           (spoiler | ||||||
|             ? '<button class="mt-btn-dark mt-btn-spoiler">' + |             ? '<button class="mt-btn-dark mt-btn-spoiler">' + | ||||||
| @ -868,8 +889,16 @@ export class Init { | |||||||
|           '<div class="mt-post-media ' + |           '<div class="mt-post-media ' + | ||||||
|           (spoiler ? "mt-post-media-spoiler " : "") + |           (spoiler ? "mt-post-media-spoiler " : "") + | ||||||
|           this.mtSettings.spinnerClass + |           this.mtSettings.spinnerClass + | ||||||
|           '" data-video-url="' + |           '" data-media-type="' + | ||||||
|  |           m.type + | ||||||
|  |           '" data-media-url-hd="' + | ||||||
|           m.url + |           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%/' + |           '" style="padding-top: calc(100%/' + | ||||||
|           m.meta.small.aspect + |           m.meta.small.aspect + | ||||||
|           ')">' + |           ')">' + | ||||||
| @ -881,14 +910,24 @@ export class Init { | |||||||
|           '<img src="' + |           '<img src="' + | ||||||
|           m.preview_url + |           m.preview_url + | ||||||
|           '" alt="' + |           '" alt="' + | ||||||
|           (m.description ? this.#escapeHtml(m.description) : "") + |           (m.description ? this.#escapeHTML(m.description) : "") + | ||||||
|           '" loading="lazy" />' + |           '" 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>"; |           "</div>"; | ||||||
|       } else { |       } else { | ||||||
|         media = |         media = | ||||||
|           '<div class="mt-post-media ' + |           '<div class="mt-post-media ' + | ||||||
|           (spoiler ? "mt-post-media-spoiler " : "") + |           (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%/' + |           '" style="padding-top: calc(100%/' + | ||||||
|           m.meta.small.aspect + |           m.meta.small.aspect + | ||||||
|           ')">' + |           ')">' + | ||||||
| @ -899,7 +938,7 @@ export class Init { | |||||||
|             : "") + |             : "") + | ||||||
|           '<video controls src="' + |           '<video controls src="' + | ||||||
|           m.url + |           m.url + | ||||||
|           '"></video>' + |           '" loop></video>' + | ||||||
|           "</div>"; |           "</div>"; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @ -907,16 +946,234 @@ export class Init { | |||||||
|     return media; |     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 |    * Replace the video preview image by the video player | ||||||
|    * @param {event} e User interaction trigger |    * @param {event} e User interaction trigger | ||||||
|    */ |    */ | ||||||
|   #loadPostVideo(e) { |   #loadPostVideo(e) { | ||||||
|     const parentNode = e.target.closest("[data-video-url]"); |     const parentNode = e.target.closest("[data-media-type]"); | ||||||
|     const videoUrl = parentNode.dataset.videoUrl; |     const urlVideo = parentNode.dataset.mediaUrlHd; | ||||||
|     parentNode.replaceChildren(); |     parentNode.replaceChildren(); | ||||||
|     parentNode.innerHTML = |     parentNode.innerHTML = `<video controls src="${urlVideo}" autoplay loop></video>`; | ||||||
|       '<video controls src="' + videoUrl + '" autoplay></video>'; |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
| @ -924,28 +1181,29 @@ export class Init { | |||||||
|    * @param {event} e User interaction trigger |    * @param {event} e User interaction trigger | ||||||
|    */ |    */ | ||||||
|   #toogleSpoiler(e) { |   #toogleSpoiler(e) { | ||||||
|     const nextSibling = e.target.nextSibling; |     const target = e.target; | ||||||
|  |     const nextSibling = target.nextSibling; | ||||||
|     if ( |     if ( | ||||||
|       nextSibling.localName === "img" || |       nextSibling.localName === "img" || | ||||||
|       nextSibling.localName === "audio" || |       nextSibling.localName === "audio" || | ||||||
|       nextSibling.localName === "video" |       nextSibling.localName === "video" | ||||||
|     ) { |     ) { | ||||||
|       e.target.parentNode.classList.remove("mt-post-media-spoiler"); |       target.parentNode.classList.remove("mt-post-media-spoiler"); | ||||||
|       e.target.style.display = "none"; |       target.style.display = "none"; | ||||||
|     } else if ( |     } else if ( | ||||||
|       nextSibling.classList.contains("spoiler-txt-hidden") || |       nextSibling.classList.contains("spoiler-txt-hidden") || | ||||||
|       nextSibling.classList.contains("spoiler-txt-visible") |       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.remove("spoiler-txt-hidden"); | ||||||
|         nextSibling.classList.add("spoiler-txt-visible"); |         nextSibling.classList.add("spoiler-txt-visible"); | ||||||
|         e.target.setAttribute("aria-expanded", "true"); |         target.setAttribute("aria-expanded", "true"); | ||||||
|         e.target.textContent = this.mtSettings.btnShowLess; |         target.textContent = this.mtSettings.btnShowLess; | ||||||
|       } else { |       } else { | ||||||
|         nextSibling.classList.remove("spoiler-txt-visible"); |         nextSibling.classList.remove("spoiler-txt-visible"); | ||||||
|         nextSibling.classList.add("spoiler-txt-hidden"); |         nextSibling.classList.add("spoiler-txt-hidden"); | ||||||
|         e.target.setAttribute("aria-expanded", "false"); |         target.setAttribute("aria-expanded", "false"); | ||||||
|         e.target.textContent = this.mtSettings.btnShowMore; |         target.textContent = this.mtSettings.btnShowMore; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @ -966,7 +1224,7 @@ export class Init { | |||||||
|           '"><img src="' + |           '"><img src="' + | ||||||
|           c.image + |           c.image + | ||||||
|           '" alt="' + |           '" alt="' + | ||||||
|           this.#escapeHtml(c.image_description) + |           this.#escapeHTML(c.image_description) + | ||||||
|           '" loading="lazy" /></div>' |           '" loading="lazy" /></div>' | ||||||
|         : '<div class="mt-post-preview-noImage">📄</div>') + |         : '<div class="mt-post-preview-noImage">📄</div>') + | ||||||
|       "</div>" + |       "</div>" + | ||||||
| @ -1032,25 +1290,26 @@ export class Init { | |||||||
|         } else if (this.mtSettings.timelineType === "local") { |         } else if (this.mtSettings.timelineType === "local") { | ||||||
|           btnSeeMorePath = "public/local"; |           btnSeeMorePath = "public/local"; | ||||||
|         } |         } | ||||||
|         const btnSeeMoreHTML = |         const btnSeeMoreHTML = ` | ||||||
|           '<a class="mt-btn-violet btn-see-more" href="' + |           <a class="mt-btn-violet btn-see-more" href="${ | ||||||
|           this.mtSettings.instanceUrl + |             this.mtSettings.instanceUrl | ||||||
|           "/" + |           }/${this.#escapeHTML( | ||||||
|           this.#escapeHtml(btnSeeMorePath) + |           btnSeeMorePath | ||||||
|           '" rel="nofollow noopener noreferrer" target="_blank">' + |         )}" rel="nofollow noopener noreferrer" target="_blank"> | ||||||
|           this.mtSettings.btnSeeMore + |             ${this.mtSettings.btnSeeMore} | ||||||
|           "</a>"; |           </a>`; | ||||||
| 
 | 
 | ||||||
|         containerFooter.insertAdjacentHTML("beforeend", btnSeeMoreHTML); |         containerFooter.insertAdjacentHTML("beforeend", btnSeeMoreHTML); | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       // Create button to refresh the timeline
 |       // Create button to refresh the timeline
 | ||||||
|       if (this.mtSettings.btnReload) { |       if (this.mtSettings.btnReload) { | ||||||
|         const btnReloadHTML = |         const btnReloadHTML = ` | ||||||
|           '<button class="mt-btn-violet btn-refresh">' + |           <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>' + |             <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"/> | ||||||
|           this.mtSettings.btnReload + |             </svg> | ||||||
|           "</button>"; |               ${this.mtSettings.btnReload} | ||||||
|  |           </button>`; | ||||||
| 
 | 
 | ||||||
|         containerFooter.insertAdjacentHTML("beforeend", btnReloadHTML); |         containerFooter.insertAdjacentHTML("beforeend", btnReloadHTML); | ||||||
| 
 | 
 | ||||||
| @ -1068,39 +1327,57 @@ export class Init { | |||||||
|    */ |    */ | ||||||
|   #setPostsInteracion() { |   #setPostsInteracion() { | ||||||
|     this.mtBodyNode.addEventListener("click", (e) => { |     this.mtBodyNode.addEventListener("click", (e) => { | ||||||
|  |       const target = e.target; | ||||||
|  |       const localName = target.localName; | ||||||
|  |       const parentNode = target.parentNode; | ||||||
|  | 
 | ||||||
|       // Check if post cointainer was clicked
 |       // Check if post cointainer was clicked
 | ||||||
|       if ( |       if ( | ||||||
|         e.target.localName == "article" || |         localName == "article" || | ||||||
|         e.target.offsetParent?.localName == "article" || |         target.offsetParent?.localName == "article" || | ||||||
|         (e.target.localName == "img" && |         (localName == "img" && | ||||||
|           !e.target.parentNode.getAttribute("data-video-url")) |           this.mtSettings.disableCarousel && | ||||||
|  |           parentNode.getAttribute("data-media-type") !== "video" && | ||||||
|  |           parentNode.getAttribute("data-media-type") !== "gifv") | ||||||
|       ) { |       ) { | ||||||
|         this.#openPostUrl(e); |         this.#openPostUrl(e); | ||||||
|       } |       } | ||||||
|  | 
 | ||||||
|       // Check if Show More/Less button was clicked
 |       // Check if Show More/Less button was clicked
 | ||||||
|       if ( |       if ( | ||||||
|         e.target.localName == "button" && |         localName == "button" && | ||||||
|         e.target.classList.contains("mt-btn-spoiler") |         target.classList.contains("mt-btn-spoiler") | ||||||
|       ) { |       ) { | ||||||
|         this.#toogleSpoiler(e); |         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
 |       // Check if video preview image or play icon/button was clicked
 | ||||||
|       if ( |       if ( | ||||||
|         e.target.className == "mt-post-media-play-icon" || |         target.className == "mt-btn-play" || | ||||||
|         (e.target.localName == "svg" && |         (localName == "svg" && parentNode.className == "mt-btn-play") || | ||||||
|           e.target.parentNode.className == "mt-post-media-play-icon") || |         (localName == "path" && | ||||||
|         (e.target.localName == "path" && |           parentNode.parentNode.className == "mt-btn-play") || | ||||||
|           e.target.parentNode.parentNode.className == |         (localName == "img" && | ||||||
|             "mt-post-media-play-icon") || |           (parentNode.getAttribute("data-media-type") === "video" || | ||||||
|         (e.target.localName == "img" && |             parentNode.getAttribute("data-media-type") === "gifv")) | ||||||
|           e.target.parentNode.getAttribute("data-video-url")) |  | ||||||
|       ) { |       ) { | ||||||
|         this.#loadPostVideo(e); |         this.#loadPostVideo(e); | ||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
|     this.mtBodyNode.addEventListener("keydown", (e) => { |     this.mtBodyNode.addEventListener("keydown", (e) => { | ||||||
|  |       const localName = e.target.localName; | ||||||
|       // Check if Enter key was pressed with focus in an article
 |       // 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); |         this.#openPostUrl(e); | ||||||
|       } |       } | ||||||
|     }); |     }); | ||||||
| @ -1118,6 +1395,7 @@ export class Init { | |||||||
|       e.target.localName !== "button" && |       e.target.localName !== "button" && | ||||||
|       e.target.localName !== "bdi" && |       e.target.localName !== "bdi" && | ||||||
|       e.target.localName !== "time" && |       e.target.localName !== "time" && | ||||||
|  |       !e.target.classList.contains("mt-post-media-spoiler") && | ||||||
|       e.target.className !== "mt-post-preview-noImage" && |       e.target.className !== "mt-post-preview-noImage" && | ||||||
|       e.target.parentNode.className !== "mt-post-avatar-image-big" && |       e.target.parentNode.className !== "mt-post-avatar-image-big" && | ||||||
|       e.target.parentNode.className !== "mt-post-avatar-image-small" && |       e.target.parentNode.className !== "mt-post-avatar-image-small" && | ||||||
| @ -1155,12 +1433,12 @@ export class Init { | |||||||
|    */ |    */ | ||||||
|   #showError(t, i) { |   #showError(t, i) { | ||||||
|     const icon = i || "❌"; |     const icon = i || "❌"; | ||||||
|     this.mtBodyNode.innerHTML = |     this.mtBodyNode.innerHTML = ` | ||||||
|       '<div class="mt-error"><span class="mt-error-icon">' + |       <div class="mt-error"> | ||||||
|       icon + |         <span class="mt-error-icon">${icon}</span> | ||||||
|       '</span><br/><strong>Oops, something\'s happened:</strong><br/><div class="mt-error-message">' + |         <strong>Oops, something's happened:</strong> | ||||||
|       t + |         <div class="mt-error-message">${t}</div> | ||||||
|       "</div></div>"; |       </div>`; | ||||||
|     this.mtBodyNode.setAttribute("role", "none"); |     this.mtBodyNode.setAttribute("role", "none"); | ||||||
|     throw new Error( |     throw new Error( | ||||||
|       "Stopping the script due to an error building the timeline." |       "Stopping the script due to an error building the timeline." | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 i.j
						i.j