Merge branch 'fix/csp-improvements' into 'master'

Fix/CSP improvements

See merge request idotj/mastodon-embed-feed-timeline!20
This commit is contained in:
i.j 2023-09-04 07:01:21 +00:00
commit 30e393cb0a
No known key found for this signature in database
5 changed files with 112 additions and 72 deletions

View File

@ -1,4 +1,8 @@
v3.8.2 - xx/08/2023 v3.9.0 - 02/09/2023
- Fix Content Security Policy
- Fix account name shown
v3.8.2 - 26/08/2023
- Add support to customized emojis - Add support to customized emojis
- Javascript refactoring to allow multiple requests - Javascript refactoring to allow multiple requests

View File

@ -1,4 +1,4 @@
/* Mastodon embed feed timeline v3.8.2 */ /* Mastodon embed feed timeline v3.9.0 */
/* More info at: */ /* More info at: */
/* https://gitlab.com/idotj/mastodon-embed-feed-timeline */ /* https://gitlab.com/idotj/mastodon-embed-feed-timeline */
@ -93,28 +93,34 @@ html[data-theme="dark"] {
margin-bottom: 0; margin-bottom: 0;
} }
/* User icon */ /* User avatar and name */
.mt-avatar { .mt-avatar {
width: 3rem;
height: 3rem;
position: absolute; position: absolute;
top: 1rem; top: 1rem;
left: 0.25rem; left: 0.25rem;
width: 3rem;
height: 3rem;
background-repeat: no-repeat;
background-position: 50% 50%;
background-size: contain;
background-color: var(--bg-color);
border-radius: 0.25rem; border-radius: 0.25rem;
overflow: hidden;
} }
.mt-avatar-boosted { .mt-avatar-image img {
width: 2.5rem; width: 100%;
height: 2.5rem; height: auto;
} }
.mt-avatar-booster { .mt-avatar-image .mt-avatar-boosted {
width: 2.25rem;
height: 2.25rem;
border-radius: 0.25rem;
overflow: hidden;
}
.mt-avatar-image .mt-avatar-account {
width: 1.5rem; width: 1.5rem;
height: 1.5rem; height: 1.5rem;
top: 1.5rem; top: 1.5rem;
left: 1.5rem; left: 1.5rem;
position: absolute;
border-radius: 0.25rem;
overflow: hidden;
} }
.mt-user { .mt-user {
display: table; display: table;
@ -157,27 +163,6 @@ html[data-theme="dark"] {
width: auto; width: auto;
} }
.mt-error {
position: absolute;
display: flex;
flex-direction: column;
height: calc(100% - 3.5rem);
width: calc(100% - 4.5rem);
justify-content: center;
align-items: center;
color: var(--error-text-color);
padding: 0.75rem;
text-align: center;
}
.mt-error-icon {
font-size: 2rem;
}
.mt-error-message {
padding: 1rem 0;
}
.mt-error-message hr {
color: var(--line-gray-color);
}
/* Poll */ /* Poll */
.toot-poll { .toot-poll {
@ -252,7 +237,6 @@ html[data-theme="dark"] {
min-height: 4rem; min-height: 4rem;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
border: 1px solid var(--line-gray-color); border: 1px solid var(--line-gray-color);
border-radius: 0.5rem; border-radius: 0.5rem;
color: var(--link-color); color: var(--link-color);
@ -308,7 +292,30 @@ html[data-theme="dark"] {
font-size: 0.75rem; font-size: 0.75rem;
} }
/* Loading-spinner */ /* Error */
.mt-error {
position: absolute;
display: flex;
flex-direction: column;
height: calc(100% - 3.5rem);
width: calc(100% - 4.5rem);
justify-content: center;
align-items: center;
color: var(--error-text-color);
padding: 0.75rem;
text-align: center;
}
.mt-error-icon {
font-size: 2rem;
}
.mt-error-message {
padding: 1rem 0;
}
.mt-error-message hr {
color: var(--line-gray-color);
}
/* Loading spinner */
.mt-body > .loading-spinner { .mt-body > .loading-spinner {
position: absolute; position: absolute;
width: 3rem; width: 3rem;
@ -332,7 +339,7 @@ html[data-theme="dark"] {
text-align: center; text-align: center;
} }
/* Hidden element */ /* Hidden elements */
.visually-hidden { .visually-hidden {
position: absolute !important; position: absolute !important;
width: 1px !important; width: 1px !important;

View File

@ -1,5 +1,5 @@
/** /**
* Mastodon embed feed timeline v3.8.2 * Mastodon embed feed timeline v3.9.0
* More info at: * More info at:
* https://gitlab.com/idotj/mastodon-embed-feed-timeline * https://gitlab.com/idotj/mastodon-embed-feed-timeline
*/ */
@ -13,6 +13,9 @@ window.addEventListener("load", () => {
// Id of the <div> containing the timeline // Id of the <div> containing the timeline
container_body_id: "mt-body", container_body_id: "mt-body",
// Class name for the loading spinner
spinner_class: "loading-spinner",
// Preferred color theme: 'light', 'dark' or 'auto'. Default: auto // Preferred color theme: 'light', 'dark' or 'auto'. Default: auto
default_theme: "auto", default_theme: "auto",
@ -66,6 +69,8 @@ window.addEventListener("load", () => {
* Trigger main function to build the timeline * Trigger main function to build the timeline
*/ */
const MastodonApi = function (params_) { const MastodonApi = function (params_) {
this.CONTAINER_BODY_ID = params_.container_body_id || "mt-body";
this.SPINNER_CLASS = params_.spinner_class || "loading-spinner";
this.DEFAULT_THEME = params_.default_theme || "auto"; this.DEFAULT_THEME = params_.default_theme || "auto";
this.INSTANCE_URL = params_.instance_url; this.INSTANCE_URL = params_.instance_url;
this.USER_ID = params_.user_id || ""; this.USER_ID = params_.user_id || "";
@ -95,7 +100,7 @@ const MastodonApi = function (params_) {
this.LINK_SEE_MORE = params_.link_see_more; this.LINK_SEE_MORE = params_.link_see_more;
this.FETCHED_DATA = {}; this.FETCHED_DATA = {};
this.mtBodyContainer = document.getElementById(params_.container_body_id); this.mtBodyContainer = document.getElementById(this.CONTAINER_BODY_ID);
this.buildTimeline(); this.buildTimeline();
}; };
@ -164,6 +169,9 @@ MastodonApi.prototype.buildTimeline = async function () {
linkSeeMore linkSeeMore
); );
} }
// Control loading spinners
this.manageSpinner();
} }
// Toot interactions // Toot interactions
@ -172,7 +180,9 @@ MastodonApi.prototype.buildTimeline = async function () {
if ( if (
e.target.localName == "article" || e.target.localName == "article" ||
e.target.offsetParent.localName == "article" || e.target.offsetParent.localName == "article" ||
e.target.localName == "img" (e.target.localName == "img" &&
e.target.offsetParent.className !== "mt-avatar" &&
e.target.offsetParent.className !== "mt-avatar-account")
) { ) {
openTootURL(e); openTootURL(e);
} }
@ -355,17 +365,23 @@ MastodonApi.prototype.assambleToot = function (c, i) {
avatar = avatar =
'<a href="' + '<a href="' +
c.reblog.account.url + c.reblog.account.url +
'" class="mt-avatar mt-avatar-boosted" style="background-image:url(' + '" class="mt-avatar" rel="nofollow noopener noreferrer" target="_blank">' +
'<div class="mt-avatar-image">' +
'<div class="mt-avatar-boosted">' +
'<img src="' +
c.reblog.account.avatar + c.reblog.account.avatar +
');" rel="nofollow noopener noreferrer" target="_blank">' + '" alt="' +
'<div class="mt-avatar mt-avatar-booster" style="background-image:url(' + c.reblog.account.username +
c.account.avatar + ' avatar" loading="lazy" />' +
');">' +
"</div>" + "</div>" +
'<span class="visually-hidden">' + '<div class="mt-avatar-account">' +
'<img src="' +
c.account.avatar +
'" alt="' +
c.account.username + c.account.username +
" avatar" + ' avatar" loading="lazy" />' +
"</span>" + "</div>" +
"</div>" +
"</a>"; "</a>";
// User name and url // User name and url
@ -374,8 +390,10 @@ MastodonApi.prototype.assambleToot = function (c, i) {
'<a href="' + '<a href="' +
c.reblog.account.url + c.reblog.account.url +
'" rel="nofollow noopener noreferrer" target="_blank">' + '" rel="nofollow noopener noreferrer" target="_blank">' +
c.reblog.account.username + (c.reblog.account.display_name
'<span class="visually-hidden"> post</span>' + ? c.reblog.account.display_name
: c.reblog.account.username) +
'<span class="visually-hidden"> account</span>' +
"</a>" + "</a>" +
"</div>"; "</div>";
@ -390,13 +408,14 @@ MastodonApi.prototype.assambleToot = function (c, i) {
avatar = avatar =
'<a href="' + '<a href="' +
c.account.url + c.account.url +
'" class="mt-avatar" style="background-image:url(' + '" class="mt-avatar" rel="nofollow noopener noreferrer" target="_blank">' +
'<div class="mt-avatar-image">' +
'<img src="' +
c.account.avatar + c.account.avatar +
');" rel="nofollow noopener noreferrer" target="_blank">' + '" alt="' +
'<span class="visually-hidden">' +
c.account.username + c.account.username +
" avatar" + ' avatar" loading="lazy" />' +
"</span>" + "</div>" +
"</a>"; "</a>";
// User name and url // User name and url
@ -405,8 +424,8 @@ MastodonApi.prototype.assambleToot = function (c, i) {
'<a href="' + '<a href="' +
c.account.url + c.account.url +
'" rel="nofollow noopener noreferrer" target="_blank">' + '" rel="nofollow noopener noreferrer" target="_blank">' +
c.account.username + (c.account.display_name ? c.account.display_name : c.account.username) +
'<span class="visually-hidden"> post</span>' + '<span class="visually-hidden"> account</span>' +
"</a>" + "</a>" +
"</div>"; "</div>";
@ -636,9 +655,11 @@ MastodonApi.prototype.placeMedias = function (m, s) {
const pic = const pic =
'<div class="toot-media ' + '<div class="toot-media ' +
(spoiler ? "toot-media-spoiler" : "") + (spoiler ? "toot-media-spoiler" : "") +
' img-ratio14_7 loading-spinner">' + " img-ratio14_7 " +
this.SPINNER_CLASS +
'">' +
(spoiler ? '<button class="spoiler-link">Show content</button>' : "") + (spoiler ? '<button class="spoiler-link">Show content</button>' : "") +
'<img onload="removeSpinner(this)" onerror="removeSpinner(this)" src="' + '<img src="' +
m.preview_url + m.preview_url +
'" alt="' + '" alt="' +
(m.description ? m.description : "") + (m.description ? m.description : "") +
@ -659,7 +680,9 @@ MastodonApi.prototype.placePreviewLink = function (c) {
c.url + c.url +
'" class="toot-preview-link" target="_blank" rel="noopener noreferrer">' + '" class="toot-preview-link" target="_blank" rel="noopener noreferrer">' +
(c.image (c.image
? '<div class="toot-preview-image"><img onload="removeSpinner(this)" onerror="removeSpinner(this)" src="' + ? '<div class="toot-preview-image ' +
this.SPINNER_CLASS +
'"><img src="' +
c.image + c.image +
'" alt="" loading="lazy" /></div>' '" alt="" loading="lazy" /></div>'
: '<div class="toot-preview-noImage">📄</div>') + : '<div class="toot-preview-noImage">📄</div>') +
@ -714,16 +737,22 @@ MastodonApi.prototype.formatDate = function (d) {
}; };
/** /**
* Loading spinner * Add/Remove event listener for loading spinner
* @param {object} e Image containing the spinner
*/ */
const removeSpinner = function (e) { MastodonApi.prototype.manageSpinner = function () {
const spinnerCSS = "loading-spinner"; // Remove CSS class to container and listener to images
const spinnerCSS = this.SPINNER_CLASS;
// Find closest parent container (1st, 2nd or 3rd level) const removeSpinner = function () {
let spinnerContainer = e.closest("." + spinnerCSS); this.parentNode.classList.remove(spinnerCSS);
this.removeEventListener("load", removeSpinner);
if (spinnerContainer) { this.removeEventListener("error", removeSpinner);
spinnerContainer.classList.remove(spinnerCSS); };
}
// Add listener to images
this.mtBodyContainer
.querySelectorAll(`.${this.SPINNER_CLASS} > img`)
.forEach((e) => {
e.addEventListener("load", removeSpinner);
e.addEventListener("error", removeSpinner);
});
}; };

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long