From f6905af76c162a0f11994857208786f7d9468897 Mon Sep 17 00:00:00 2001 From: Chris Vitalos Date: Wed, 11 Oct 2023 20:42:24 -0400 Subject: [PATCH] commit mastodon-timeline with tag v3.10.1-1 --- css/mastodon-timeline-3.10.0-1.css | 394 --------- ...0-2.css => mastodon-timeline-3.10.1-1.css} | 33 +- js/mastodon-timeline-3.10.0-2.js | 834 ------------------ ...0.0-1.js => mastodon-timeline-3.10.1-1.js} | 72 +- 4 files changed, 78 insertions(+), 1255 deletions(-) delete mode 100644 css/mastodon-timeline-3.10.0-1.css rename css/{mastodon-timeline-3.10.0-2.css => mastodon-timeline-3.10.1-1.css} (92%) delete mode 100644 js/mastodon-timeline-3.10.0-2.js rename js/{mastodon-timeline-3.10.0-1.js => mastodon-timeline-3.10.1-1.js} (94%) diff --git a/css/mastodon-timeline-3.10.0-1.css b/css/mastodon-timeline-3.10.0-1.css deleted file mode 100644 index de18b4e..0000000 --- a/css/mastodon-timeline-3.10.0-1.css +++ /dev/null @@ -1,394 +0,0 @@ -/* Mastodon embed feed timeline v3.10.0-1 */ -/* More info at: */ -/* https://gitlab.com/clvgt12/mastodon-embed-feed-timeline */ - -/* Variables */ -:root { - --text-max-lines: none; -} - -/* Theme colors */ -:root, -html[data-theme="light"] { - --bg-color: #fff; - --bg-hover-color: #d9e1e8; - --line-gray-color: #c0cdd9; - --content-text: #000; - --link-color: #3a3bff; - --contrast-gray-color: #606984; - --error-text-color: #8b0000; -} -html[data-theme="dark"] { - --bg-color: #fff; - --bg-hover-color: #d9e1e8; - --line-gray-color: #c0cdd9; - --content-text: #000; - --link-color: #3a3bff; - --contrast-gray-color: #606984; - --error-text-color: #8b0000; -} - -/* Main container */ -.mt-container { - height: 100%; - overflow-y: auto; - position: relative; - background-color: var(--bg-color); - scrollbar-color: var(--line-gray-color) var(--bg-color); - scrollbar-width: thin; -} -.mt-container::-webkit-scrollbar { - width: 0.25rem; - height: 0.25rem; -} -.mt-container::-webkit-scrollbar-thumb { - background-color: var(--line-gray-color); - border: none; - border-radius: 3rem; -} -.mt-container::-webkit-scrollbar-thumb:hover, -.mt-container::-webkit-scrollbar-thumb:active { - background-color: var(--line-gray-color); -} -.mt-container::-webkit-scrollbar-track { - background-color: var(--bg-color); - border: none; - border-radius: 0; -} -.mt-container::-webkit-scrollbar-track:hover, -.mt-container::-webkit-scrollbar-track:active, -.mt-container::-webkit-scrollbar-corner { - background-color: var(--bg-color); -} -.mt-container a:link, -.mt-container a:active, -.mt-container a { - text-decoration: none; - color: var(--link-color); -} -.mt-container a:not(.mt-toot-preview):hover { - text-decoration: underline; -} -.mt-body { - padding: 1rem clamp(0.25rem, 4vw, 1.5rem); - white-space: pre-wrap; - word-wrap: break-word; -} -.mt-body .invisible { - font-size: 0; - line-height: 0; - display: inline-block; - width: 0; - height: 0; - position: absolute; -} - -.mt-body a { - color: var(--link-color); -} - -/* Toot container */ -.mt-toot { - margin: 0.25rem; - padding: 1rem 0.5rem 1.5rem 0.5rem; - position: relative; - min-height: 3.75rem; - background-color: var(--bg-color); - border-bottom: 1px solid var(--line-gray-color); - font-family: sans-serif; -} -.mt-toot:hover, -.mt-toot:focus { - cursor: pointer; - background-color: var(--bg-hover-color); -} -.mt-toot p:last-child { - margin-bottom: 0; -} - -/* User avatar */ -.mt-toot-avatar { - margin-right: 0.75rem; -} -.mt-toot-avatar-standard { - width: 2.25rem; - height: 2.25rem; -} -.mt-toot-avatar-boosted { - width: 3rem; - height: 3rem; - position: relative; -} -.mt-toot-avatar-image-big img { - aspect-ratio: 1/1; - width: 2.25rem; - height: 2.25rem; - border-radius: 0.25rem; - overflow: hidden; -} -.mt-toot-avatar-image-small img { - aspect-ratio: 1/1; - width: 1.5rem; - height: 1.5rem; - top: 1.5rem; - left: 1.5rem; - position: absolute; - border-radius: 0.25rem; - overflow: hidden; -} - -/* User name and date */ -.mt-toot-header { - display: flex; - justify-content: space-between; - align-items: flex-start; - margin-bottom: 1rem; -} -.mt-toot-header-user { - font-weight: 600; - margin-top: 0.5rem; - padding-right: 1rem; -} -.mt-toot-header-user > a { - display: flex; - align-items: flex-start; - color: var(--content-text) !important; - overflow-wrap: anywhere; -} -.mt-toot-header-date { - font-size: 0.75rem; - text-align: right; - margin: 0.5rem 0 0 auto; -} -.mt-toot-header-date > a { - color: var(--contrast-gray-color) !important; -} - -/* Text */ -.mt-toot-text { - margin-bottom: 1rem; - color: var(--content-text); -} -.mt-toot-text .spoiler-btn { - display: inline-block; -} -.mt-toot-text .spoiler-text-hidden { - display: none; -} -.mt-toot-text.truncate { - display: -webkit-box; - overflow: hidden; - -webkit-line-clamp: var(--text-max-lines); - -webkit-box-orient: vertical; -} -.mt-toot-text:not(.truncate) .ellipsis::after { - content: "..."; -} -.mt-toot-text blockquote { - border-left: 0.25rem solid var(--line-gray-color); - margin-left: 0; - padding-left: 0.5rem; -} -.mt-toot-header-user .custom-emoji, -.mt-toot-text .custom-emoji { - height: 1.5rem; - min-width: 1.5rem; - margin-bottom: -0.25rem; - width: auto; -} - -/* Poll */ -.mt-toot-poll { - margin-bottom: 1rem; - color: var(--content-text); -} -.mt-toot-poll ul { - list-style: none; - padding: 0; - margin: 0; -} -.mt-toot-poll ul li { - font-size: 0.9rem; - margin-bottom: 0.5rem; -} -.mt-toot-poll ul li:not(:last-child) { - margin-bottom: 0.25rem; -} -.mt-toot-poll ul li:before { - content: "◯"; - padding-right: 0.5rem; -} - -/* Medias */ -.mt-toot-media { - overflow: hidden; - margin-bottom: 1rem; - border-radius: 0.75rem; -} -.mt-toot-media > .spoiler-btn { - position: absolute; - top: 50%; - left: 50%; - z-index: 1; - transform: translate(-50%, -50%); -} -.mt-toot-media-spoiler > img { - filter: blur(2rem); -} -.img-ratio14_7 { - position: relative; - padding-top: 56.95%; - width: 100%; -} -.img-ratio14_7 > img { - width: 100%; - height: auto; - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - text-align: center; -} - -/* Preview link */ -.mt-toot-preview { - min-height: 4rem; - display: flex; - flex-direction: column; - border: 1px solid var(--line-gray-color); - border-radius: 0.75rem; - color: var(--link-color); - font-size: 0.8rem; - margin: 1rem 0; - overflow: hidden; -} -.mt-toot-preview-image { - width: 100%; - align-self: stretch; -} -.mt-toot-preview-image img { - display: block; - width: 100%; - height: 100%; - object-fit: cover; -} -.mt-toot-preview-noImage { - width: 40%; - font-size: 1.5rem; - align-self: inherit; - text-align: left; -} -.mt-toot-preview-content { - width: 95%; - display: flex; - align-self: center; - flex-direction: column; - padding: 0.5rem 1rem; - gap: 0.5rem; -} -.mt-toot-preview-title { - font-weight: 600; - font-size: 1.0rem; - font-family: serif; -} - -/* Spoiler button */ -.spoiler-btn { - border-radius: 2px; - background-color: var(--line-gray-color); - border: 0; - color: var(--content-text); - font-weight: 700; - font-size: 0.7rem; - padding: 0 0.35rem; - text-transform: uppercase; - line-height: 1.25rem; - cursor: pointer; - vertical-align: top; -} - -/* Counter bar */ -.mt-toot-counter-bar { - display: flex; - min-width: 6rem; - max-width: 40rem; - justify-content: space-between; - color: var(--contrast-gray-color); -} -.mt-toot-counter-bar-replies, -.mt-toot-counter-bar-reblog, -.mt-toot-counter-bar-favorites { - display: flex; - font-size: 0.75rem; - gap: 0.25rem; - align-items: center; - opacity: 0.5; -} -.mt-toot-counter-bar-replies > svg, -.mt-toot-counter-bar-reblog > svg, -.mt-toot-counter-bar-favorites > svg { - width: 1rem; - fill: var(--contrast-gray-color); -} - -/* Error */ -.mt-error { - display: flex; - flex-direction: column; - 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 { - position: absolute; - width: 3rem; - height: 3rem; - margin: auto; - top: calc(50% - 1.5rem); - right: calc(50% - 1.5rem); -} -.loading-spinner { - background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns:svg='http://www.w3.org/2000/svg' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' version='1.0' viewBox='0 0 128 128' %3E%3Cg%3E%3Cpath d='M64 128A64 64 0 0 1 18.34 19.16L21.16 22a60 60 0 1 0 52.8-17.17l.62-3.95A64 64 0 0 1 64 128z' fill='%23404040'/%3E%3CanimateTransform attributeName='transform' type='rotate' from='0 64 64' to='360 64 64' dur='1000ms' repeatCount='indefinite'%3E%3C/animateTransform%3E%3C/g%3E%3C/svg%3E"); - background-repeat: no-repeat; - background-position: center center; - background-color: transparent; - background-size: min(2.5rem, calc(100% - 0.5rem)); -} - -/* Footer (See more link) */ -.mt-footer { - margin: 1rem auto 2rem auto; - padding: 0 2rem; - text-align: center; - font-family: sans-serif; -} - -.mt-footer a { - color: var(--link-color); -} - -/* Hidden elements */ -.visually-hidden { - position: absolute !important; - width: 1px !important; - height: 1px !important; - padding: 0 !important; - margin: -1px !important; - overflow: hidden !important; - clip: rect(0, 0, 0, 0) !important; - white-space: nowrap !important; - border: 0 !important; -} \ No newline at end of file diff --git a/css/mastodon-timeline-3.10.0-2.css b/css/mastodon-timeline-3.10.1-1.css similarity index 92% rename from css/mastodon-timeline-3.10.0-2.css rename to css/mastodon-timeline-3.10.1-1.css index 1356972..5b9d616 100644 --- a/css/mastodon-timeline-3.10.0-2.css +++ b/css/mastodon-timeline-3.10.1-1.css @@ -1,4 +1,4 @@ -/* Mastodon embed feed timeline v3.10.0-2 */ +/* Mastodon embed feed timeline v3.10.1-1 */ /* More info at: */ /* https://gitlab.com/clvgt12/mastodon-embed-feed-timeline */ @@ -83,9 +83,13 @@ html[data-theme="dark"] { height: 0; position: absolute; } - .mt-body a { - color: var(--link-color); + color: var(--link-color); + text-decoration: none; +} +.mt-body a:hover { +color: var(--link-color); +text-decoration: underline; } /* Toot container */ @@ -141,12 +145,11 @@ html[data-theme="dark"] { .mt-toot-header { display: flex; justify-content: space-between; - align-items: flex-start; + align-items: center; margin-bottom: 1rem; } .mt-toot-header-user { font-weight: 600; - margin-top: 0.5rem; padding-right: 1rem; } .mt-toot-header-user > a { @@ -154,14 +157,16 @@ html[data-theme="dark"] { align-items: flex-start; color: var(--content-text) !important; overflow-wrap: anywhere; + text-decoration: none; } .mt-toot-header-date { font-size: 0.75rem; text-align: right; - margin: 0.5rem 0 0 auto; + margin: 0 0 0 auto; } .mt-toot-header-date > a { color: var(--contrast-gray-color) !important; + text-decoration: none; } /* Text */ @@ -211,6 +216,9 @@ html[data-theme="dark"] { font-size: 0.9rem; margin-bottom: 0.5rem; } +.mt-toot-poll.mt-toot-poll-expired ul li { + color: var(--contrast-gray-color); +} .mt-toot-poll ul li:not(:last-child) { margin-bottom: 0.25rem; } @@ -218,6 +226,10 @@ html[data-theme="dark"] { content: "◯"; padding-right: 0.5rem; } +.mt-toot-poll.mt-toot-poll-expired ul li:before { + content: ""; + padding-right: 0; +} /* Medias */ .mt-toot-media { @@ -248,6 +260,7 @@ html[data-theme="dark"] { left: 50%; transform: translate(-50%, -50%); text-align: center; + color: var(--content-text); } /* Preview link */ @@ -271,6 +284,7 @@ html[data-theme="dark"] { width: 100%; height: 100%; object-fit: cover; + color: var(--content-text); } .mt-toot-preview-noImage { width: 40%; @@ -374,12 +388,17 @@ html[data-theme="dark"] { padding: unset; text-align: center; font-family: sans-serif; + font-size: 0.8rem; height: 3.0rem; background-color: var(--bg-color); } - .mt-footer a { color: var(--link-color); + text-decoration: none; +} +.mt-footer a:hover { + color: var(--link-color); + text-decoration: underline; } /* Hidden elements */ diff --git a/js/mastodon-timeline-3.10.0-2.js b/js/mastodon-timeline-3.10.0-2.js deleted file mode 100644 index da6f4c1..0000000 --- a/js/mastodon-timeline-3.10.0-2.js +++ /dev/null @@ -1,834 +0,0 @@ -/** - * Mastodon embed feed timeline v3.10.0-2 - * More info at: - * https://gitlab.com/idotj/mastodon-embed-feed-timeline - */ -/** - * This file contains modifications to the above upstream project. - * The file repository for these modifications can be found here: - * https://gitlab.com/clvgt12/mastodon-embed-feed-timeline - * - * Mastodon embed feed timeline - * Copyright (C) 2022 clvgt12 - * Copyright (C) 2021 i.j - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -/** - * Timeline settings - * Adjust these parameters to customize your timeline - */ -/** ------------------------------------------------------ -window.addEventListener("load", () => { - const mastodonTimeline = new MastodonApi({ - // Id of the
containing the timeline - container_body_id: "mt-body", - - // Class name for the loading spinner (also used in CSS file) - spinner_class: "loading-spinner", - - // Preferred color theme: 'light', 'dark' or 'auto'. Default: auto - default_theme: "auto", - - // Your Mastodon instance - instance_url: "https://mastodon.online", - - // Choose type of toots to show in the timeline: 'local', 'profile', 'hashtag'. Default: local - timeline_type: "local", - - // Your user ID on Mastodon instance. Leave empty if you didn't choose 'profile' as type of timeline - user_id: "", - - // Your user name on Mastodon instance. Leave empty if you didn't choose 'profile' as type of timeline - profile_name: "", - - // The name of the hashtag. Leave empty if you didn't choose 'hashtag' as type of timeline - hashtag_name: "", - - // Maximum amount of toots to get. Default: 20 - toots_limit: "20", - - // Hide unlisted toots. Default: don't hide - hide_unlisted: false, - - // Hide boosted toots. Default: don't hide - hide_reblog: false, - - // Hide replies toots. Default: don't hide - hide_replies: false, - - // Hide preview card if toot contains a link, photo or video from a URL. Default: don't hide - hide_preview_link: false, - - // Hide custom emojis available on the server. Default: don't hide - hide_emojos: false, - - // Converts Markdown symbol ">" at the beginning of a paragraph into a blockquote HTML tag. Ddefault: don't apply - markdown_blockquote: false, - - // Hide replies, boosts and favourites toots counter. Default: don't hide - hide_counter_bar: false, - - // Limit the text content to a maximum number of lines. Default: 0 (unlimited) - text_max_lines: "0", - - // Customize the text of the link pointing to the Mastodon page (appears after the last toot) - link_see_more: "See more posts at Mastodon", - }); -}); ------------------------------ */ -/** - * Set all variables with customized values or use default ones - * @param {object} params_ User customized values - * Trigger main function to build the timeline - */ -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.INSTANCE_URL = params_.instance_url; - this.USER_ID = params_.user_id || ""; - this.PROFILE_NAME = this.USER_ID ? params_.profile_name : ""; - this.TIMELINE_TYPE = params_.timeline_type || "local"; - this.HASHTAG_NAME = params_.hashtag_name || ""; - this.TOOTS_LIMIT = params_.toots_limit || "20"; - this.HIDE_UNLISTED = - typeof params_.hide_unlisted !== "undefined" - ? params_.hide_unlisted - : false; - this.HIDE_REBLOG = - typeof params_.hide_reblog !== "undefined" ? params_.hide_reblog : false; - this.HIDE_REPLIES = - typeof params_.hide_replies !== "undefined" ? params_.hide_replies : false; - this.HIDE_PREVIEW_LINK = - typeof params_.hide_preview_link !== "undefined" - ? params_.hide_preview_link - : false; - this.HIDE_EMOJOS = - typeof params_.hide_emojos !== "undefined" ? params_.hide_emojos : false; - this.MARKDOWN_BLOCKQUOTE = - typeof params_.markdown_blockquote !== "undefined" - ? params_.markdown_blockquote - : false; - this.HIDE_COUNTER_BAR = - params_.hide_counter_bar !== "undefined" ? params_.hide_counter_bar : false; - this.TEXT_MAX_LINES = params_.text_max_lines || "0"; - this.LINK_SEE_MORE = params_.link_see_more; - this.FETCHED_DATA = {}; - - this.mtBodyContainer = document.getElementById(this.CONTAINER_BODY_ID); - - this.buildTimeline(); -}; - -/** - * Trigger functions and construct timeline - */ -MastodonApi.prototype.buildTimeline = async function () { - // Apply color theme - this.setTheme(); - - // Get server data - await this.getTimelineData(); - - // Empty the
container - this.mtBodyContainer.innerHTML = ""; - - for (let i in this.FETCHED_DATA.timeline) { - // First filter (Public / Unlisted) - if ( - this.FETCHED_DATA.timeline[i].visibility == "public" || - (!this.HIDE_UNLISTED && - this.FETCHED_DATA.timeline[i].visibility == "unlisted") - ) { - // Second filter (Reblog / Replies) - if ( - (this.HIDE_REBLOG && this.FETCHED_DATA.timeline[i].reblog) || - (this.HIDE_REPLIES && this.FETCHED_DATA.timeline[i].in_reply_to_id) - ) { - // Nothing here (Don't append toots) - } else { - // Append toots - this.appendToot(this.FETCHED_DATA.timeline[i], Number(i)); - } - } - } - - // Check if there are toots in the container (due to filters applied) - if (this.mtBodyContainer.innerHTML === "") { - this.mtBodyContainer.setAttribute("role", "none"); - this.mtBodyContainer.innerHTML = - '
📭
Sorry, no toots to show
Got ' + - this.FETCHED_DATA.timeline.length + - ' toots from the server but due to the "hide filters" applied, no toot is shown
'; - } else { - // Insert link after last toot to visit Mastodon page - if (this.LINK_SEE_MORE) { - let linkSeeMorePath = ""; - if (this.TIMELINE_TYPE === "profile") { - linkSeeMorePath = this.PROFILE_NAME; - } else if (this.TIMELINE_TYPE === "hashtag") { - linkSeeMorePath = "tags/" + this.HASHTAG_NAME; - } else if (this.TIMELINE_TYPE === "local") { - linkSeeMorePath = "public/local"; - } - let linkSeeMore = - '"; - this.mtBodyContainer.parentNode.insertAdjacentHTML( - "beforeend", - linkSeeMore - ); - } - - // Control loading spinners - this.manageSpinner(); - } - - // Toot interactions - this.mtBodyContainer.addEventListener("click", function (e) { - // Check if toot cointainer was clicked - if ( - e.target.localName == "article" || - e.target.offsetParent?.localName == "article" || - e.target.localName == "img" - ) { - openTootURL(e); - } - // Check if Show More/Less button was clicked - if (e.target.localName == "button" && e.target.className == "spoiler-btn") { - toogleSpoiler(e); - } - }); - this.mtBodyContainer.addEventListener("keydown", function (e) { - // Check if Enter key was pressed with focus in an article - if (e.key === "Enter" && e.target.localName == "article") { - openTootURL(e); - } - }); - - /** - * Open toot in a new page avoiding any other natural link - * @param {event} e User interaction trigger - */ - const openTootURL = function (e) { - let urlToot = e.target.closest(".mt-toot").dataset.location; - if ( - e.target.localName !== "a" && - e.target.localName !== "span" && - e.target.localName !== "button" && - e.target.localName !== "time" && - e.target.className !== "mt-toot-preview-noImage" && - e.target.parentNode.className !== "mt-toot-avatar-image-big" && - e.target.parentNode.className !== "mt-toot-avatar-image-small" && - e.target.parentNode.className !== "mt-toot-preview-image" && - urlToot - ) { - window.open(urlToot, "_blank"); - } - }; - - /** - * Spoiler button - * @param {event} e User interaction trigger - */ - const toogleSpoiler = function (e) { - const nextSibling = e.target.nextSibling; - if (nextSibling.localName === "img") { - e.target.parentNode.classList.remove("mt-toot-media-spoiler"); - e.target.style.display = "none"; - } else if ( - nextSibling.classList.contains("spoiler-text-hidden") || - nextSibling.classList.contains("spoiler-text-visible") - ) { - if (e.target.textContent == "Show more") { - nextSibling.classList.remove("spoiler-text-hidden"); - nextSibling.classList.add("spoiler-text-visible"); - e.target.setAttribute("aria-expanded", "true"); - e.target.textContent = "Show less"; - } else { - nextSibling.classList.remove("spoiler-text-visible"); - nextSibling.classList.add("spoiler-text-hidden"); - e.target.setAttribute("aria-expanded", "false"); - e.target.textContent = "Show more"; - } - } - }; -}; - -/** - * Set the theme style chosen by the user or by the browser/OS - */ -MastodonApi.prototype.setTheme = function () { - /** - * Set the theme value in the tag using the attribute "data-theme" - * @param {string} theme Type of theme to apply: dark or light - */ - const setTheme = function (theme) { - document.documentElement.setAttribute("data-theme", theme); - }; - - if (this.DEFAULT_THEME === "auto") { - let systemTheme = window.matchMedia("(prefers-color-scheme: dark)"); - systemTheme.matches ? setTheme("dark") : setTheme("light"); - // Update the theme if user change browser/OS preference - systemTheme.addEventListener("change", (e) => { - e.matches ? setTheme("dark") : setTheme("light"); - }); - } else { - setTheme(this.DEFAULT_THEME); - } -}; - -/** - * Requests to the server to get all the data - */ -MastodonApi.prototype.getTimelineData = async function () { - return new Promise((resolve, reject) => { - /** - * Fetch data from server - * @param {string} url address to fetch - * @returns {object} List of objects - */ - async function fetchData(url) { - const response = await fetch(url); - - if (!response.ok) { - throw new Error( - "Failed to fetch the following URL: " + - url + - "
" + - "Error status: " + - response.status + - "
" + - "Error message: " + - response.statusText - ); - } - - const data = await response.json(); - return data; - } - - // URLs to fetch - let urls = {}; - if (this.TIMELINE_TYPE === "profile") { - urls.timeline = `${this.INSTANCE_URL}/api/v1/accounts/${this.USER_ID}/statuses?limit=${this.TOOTS_LIMIT}`; - } else if (this.TIMELINE_TYPE === "hashtag") { - urls.timeline = `${this.INSTANCE_URL}/api/v1/timelines/tag/${this.HASHTAG_NAME}?limit=${this.TOOTS_LIMIT}`; - } else if (this.TIMELINE_TYPE === "local") { - urls.timeline = `${this.INSTANCE_URL}/api/v1/timelines/public?local=true&limit=${this.TOOTS_LIMIT}`; - } - if (!this.HIDE_EMOJOS) { - urls.emojos = this.INSTANCE_URL + "/api/v1/custom_emojis"; - } - - const urlsPromises = Object.entries(urls).map(([key, url]) => { - return fetchData(url) - .then((data) => ({ [key]: data })) - .catch((error) => { - reject(new Error("Something went wrong fetching data")); - this.mtBodyContainer.innerHTML = - '

Sorry, request failed:
' + - error.message + - "
"; - this.mtBodyContainer.setAttribute("role", "none"); - return { [key]: [] }; - }); - }); - - // Fetch all urls simultaneously - Promise.all(urlsPromises).then((dataObjects) => { - this.FETCHED_DATA = dataObjects.reduce((result, dataItem) => { - return { ...result, ...dataItem }; - }, {}); - - // console.log("Timeline data fetched: ", this.FETCHED_DATA); - resolve(); - }); - }); -}; - -/** - * Inner function to add each toot in timeline container - * @param {object} c Toot content - * @param {number} i Index of toot - */ -MastodonApi.prototype.appendToot = function (c, i) { - this.mtBodyContainer.insertAdjacentHTML("beforeend", this.assambleToot(c, i)); -}; - -/** - * Build toot structure - * @param {object} c Toot content - * @param {number} i Index of toot - */ -MastodonApi.prototype.assambleToot = function (c, i) { - let avatar, user, userName, url, date, formattedDate; - - if (c.reblog) { - // BOOSTED toot - // Toot url - url = c.reblog.url; - - // Boosted avatar - avatar = - '' + - '
' + - '
' + - '' +
-      c.reblog.account.username +
-      ' avatar' + - "
" + - '
' + - '' +
-      c.account.username +
-      ' avatar' + - "
" + - "
" + - "
"; - - // User name and url - userName = this.showEmojos( - c.reblog.account.display_name - ? c.reblog.account.display_name - : c.reblog.account.username, - this.FETCHED_DATA.emojos - ); - user = - '"; - - // Date - date = c.reblog.created_at; - } else { - // STANDARD toot - // Toot url - url = c.url; - - // Avatar - avatar = - '' + - '
' + - '
' + - '' +
-      c.account.username +
-      ' avatar' + - "
" + - "
" + - "
"; - - // User name and url - userName = this.showEmojos( - c.account.display_name ? c.account.display_name : c.account.username, - this.FETCHED_DATA.emojos - ); - user = - '"; - - // Date - date = c.created_at; - } - - // Date - formattedDate = this.formatDate(date); - let timestamp = - '"; - - // Main text - let text_css = ""; - if (this.TEXT_MAX_LINES !== "0") { - text_css = "truncate"; - document.documentElement.style.setProperty( - "--text-max-lines", - this.TEXT_MAX_LINES - ); - } - - let content = ""; - if (c.spoiler_text !== "") { - content = - '
' + - c.spoiler_text + - ' ' + - '
' + - this.formatTootText(c.content) + - "
" + - "
"; - } else if ( - c.reblog && - c.reblog.content !== "" && - c.reblog.spoiler_text !== "" - ) { - content = - '
' + - c.reblog.spoiler_text + - ' ' + - '
' + - this.formatTootText(c.reblog.content) + - "
" + - "
"; - } else if ( - c.reblog && - c.reblog.content !== "" && - c.reblog.spoiler_text === "" - ) { - content = - '
' + - '
' + - this.formatTootText(c.reblog.content) + - "
" + - "
"; - } else { - content = - '
' + - '
' + - this.formatTootText(c.content) + - "
" + - "
"; - } - - // Media attachments - let media = ""; - if (c.media_attachments.length > 0) { - for (let picid in c.media_attachments) { - media = this.placeMedias(c.media_attachments[picid], c.sensitive); - } - } - if (c.reblog && c.reblog.media_attachments.length > 0) { - for (let picid in c.reblog.media_attachments) { - media = this.placeMedias( - c.reblog.media_attachments[picid], - c.reblog.sensitive - ); - } - } - - // Preview link - let previewLink = ""; - if (!this.HIDE_PREVIEW_LINK && c.card) { - if (media === "") { - previewLink = this.placePreviewLink(c.card); - } - } - - // Poll - let poll = ""; - let pollOption = ""; - if (c.poll) { - for (let i in c.poll.options) { - pollOption += "
  • " + c.poll.options[i].title + "
  • "; - } - poll = - '
    ' + "
      " + pollOption + "
    " + "
    "; - } - - // Counter bar - let counterBar = ""; - if (!this.HIDE_COUNTER_BAR) { - let repliesCount = - '
    ' + - '' + - c.replies_count + - "
    "; - - let reblogCount = - '
    ' + - '' + - c.reblogs_count + - "
    "; - - let favoritesCount = - '
    ' + - '' + - c.favourites_count + - "
    "; - - counterBar = - '
    ' + - repliesCount + - reblogCount + - favoritesCount + - "
    "; - } - - // Add all to main toot container - let toot = - '
    ' + - '
    ' + - avatar + - user + - timestamp + - "
    " + - content + - media + - previewLink + - poll + - counterBar + - "
    "; - - return toot; -}; - -/** - * Handle text changes made to toots - * @param {string} c Text content - * @returns {string} Text content modified - */ -MastodonApi.prototype.formatTootText = function (c) { - let content = c; - - // Format hashtags and mentions - content = this.addTarget2hashtagMention(content); - - // Convert emojos shortcode into images - if (!this.HIDE_EMOJOS) { - content = this.showEmojos(content, this.FETCHED_DATA.emojos); - } - - // Convert markdown styles into HTML - if (this.MARKDOWN_BLOCKQUOTE) { - content = this.replaceHTMLtag( - content, - "

    >", - "

    ", - "

    ", - "

    " - ); - } - - return content; -}; - -/** - * Add target="_blank" to all #hashtags and @mentions in the toot - * @param {string} c Text content - * @returns {string} Text content modified - */ -MastodonApi.prototype.addTarget2hashtagMention = function (c) { - let content = c.replaceAll('rel="tag"', 'rel="tag" target="_blank"'); - content = content.replaceAll( - 'class="u-url mention"', - 'class="u-url mention" target="_blank"' - ); - - return content; -}; - -/** - * Find all custom emojis shortcode and replace by image - * @param {string} c Text content - * @param {array} e List with all custom emojis - * @returns {string} Text content modified - */ -MastodonApi.prototype.showEmojos = function (c, e) { - if (c.includes(":")) { - for (const emojo of e) { - const regex = new RegExp(`\\:${emojo.shortcode}\\:`, "g"); - c = c.replace( - regex, - `Emoji ${emojo.shortcode}` - ); - } - - return c; - } else { - return c; - } -}; - -/** - * Find all start/end and replace them by another start/end - * @param {string} c Text content - * @param {string} initialTagOpen Start HTML tag to replace - * @param {string} initialTagClose End HTML tag to replace - * @param {string} replacedTagOpen New start HTML tag - * @param {string} replacedTagClose New end HTML tag - * @returns {string} Text in HTML format - */ -MastodonApi.prototype.replaceHTMLtag = function ( - c, - initialTagOpen, - initialTagClose, - replacedTagOpen, - replacedTagClose -) { - if (c.includes(initialTagOpen)) { - const regex = new RegExp(initialTagOpen + "(.*?)" + initialTagClose, "gi"); - - return c.replace(regex, replacedTagOpen + "$1" + replacedTagClose); - } else { - return c; - } -}; - -/** - * Place media - * @param {object} m Media content - * @param {boolean} s Spoiler/Sensitive status - * @returns {string} Media in HTML format - */ -MastodonApi.prototype.placeMedias = function (m, s) { - let spoiler = s || false; - const pic = - '
    ' + - (spoiler ? '' : "") + - '' +
-    (m.description ? m.description : ' + - "
    "; - - return pic; -}; - -/** - * Place preview link - * @param {object} c Preview link content - * @returns {string} Preview link in HTML format - */ -MastodonApi.prototype.placePreviewLink = function (c) { - let card = - '' + - (c.image - ? '
    ' - : '
    ') + - "
    " + - '
    ' + - (c.provider_name - ? '' + c.provider_name + "" - : "") + - '' + - c.title + - "" + - (c.author_name - ? 'By ' + c.author_name + "" - : "") + - "
    " + - "
    "; - - return card; -}; - -/** - * Format date - * @param {string} d Date in ISO format (YYYY-MM-DDTHH:mm:ss.sssZ) - * @returns {string} Date formated (MM DD, YYYY) - */ -MastodonApi.prototype.formatDate = function (d) { - const monthNames = [ - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec", - ]; - - let date = new Date(d); - - const displayDate = - monthNames[date.getMonth()] + - " " + - date.getDate() + - ", " + - date.getFullYear(); - - return displayDate; -}; - -/** - * Add/Remove event listener for loading spinner - */ -MastodonApi.prototype.manageSpinner = function () { - // Remove CSS class to container and listener to images - const spinnerCSS = this.SPINNER_CLASS; - const removeSpinner = function () { - this.parentNode.classList.remove(spinnerCSS); - this.removeEventListener("load", removeSpinner); - this.removeEventListener("error", removeSpinner); - }; - - // Add listener to images - this.mtBodyContainer - .querySelectorAll(`.${this.SPINNER_CLASS} > img`) - .forEach((e) => { - e.addEventListener("load", removeSpinner); - e.addEventListener("error", removeSpinner); - }); -}; \ No newline at end of file diff --git a/js/mastodon-timeline-3.10.0-1.js b/js/mastodon-timeline-3.10.1-1.js similarity index 94% rename from js/mastodon-timeline-3.10.0-1.js rename to js/mastodon-timeline-3.10.1-1.js index 82236a7..e15dafc 100644 --- a/js/mastodon-timeline-3.10.0-1.js +++ b/js/mastodon-timeline-3.10.1-1.js @@ -1,5 +1,5 @@ /** - * Mastodon embed feed timeline v3.10.0-1 + * Mastodon embed feed timeline v3.10.1-1 * More info at: * https://gitlab.com/idotj/mastodon-embed-feed-timeline */ @@ -183,7 +183,7 @@ MastodonApi.prototype.buildTimeline = async function () { } else if (this.TIMELINE_TYPE === "local") { linkSeeMorePath = "public/local"; } - let linkSeeMore = + const linkSeeMore = '" + '
    ' + '' +
-      c.account.username +
+      this.replaceQuotes(c.account.username) +
       ' avatar' + "
    " + "
    " + @@ -471,7 +471,7 @@ MastodonApi.prototype.assambleToot = function (c, i) { // Date formattedDate = this.formatDate(date); - let timestamp = + const timestamp = '' + '" alt="' + + this.replaceQuotes(c.image_description) + + '" loading="lazy" />' : '
    ') + "" + '
    ' + (c.provider_name - ? '' + c.provider_name + "" + ? '' + + this.parseHTMLstring(c.provider_name) + + "" : "") + '' + c.title + "" + (c.author_name - ? 'By ' + c.author_name + "" + ? '' + + this.parseHTMLstring(c.author_name) + + "" : "") + "
    " + "
    "; @@ -800,7 +812,7 @@ MastodonApi.prototype.formatDate = function (d) { "Dec", ]; - let date = new Date(d); + const date = new Date(d); const displayDate = monthNames[date.getMonth()] + @@ -812,6 +824,26 @@ MastodonApi.prototype.formatDate = function (d) { return displayDate; }; +/** + * Parse HTML string + * @param {string} s HTML string + * @returns {string} Plain text + */ +MastodonApi.prototype.parseHTMLstring = function (s) { + const parser = new DOMParser(); + const txt = parser.parseFromString(s, "text/html"); + return txt.body.textContent; +}; + +/** + * Replace quotes + * @param {string} s String + * @returns {string} String + */ +MastodonApi.prototype.replaceQuotes = function (s) { + return s.replace('"', "'"); +}; + /** * Add/Remove event listener for loading spinner */