diff --git a/.editorconfig b/.editorconfig index 3ed1a3a..45c8752 100644 --- a/.editorconfig +++ b/.editorconfig @@ -18,3 +18,4 @@ indent_style = ignore [**.min.css] indent_style = ignore + diff --git a/.gitignore b/.gitignore index e93664d..55c720a 100644 --- a/.gitignore +++ b/.gitignore @@ -29,12 +29,6 @@ coverage # nyc test coverage .nyc_output -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - # node-waf configuration .lock-wscript @@ -95,9 +89,6 @@ out # Gatsby files .cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public # vuepress build output .vuepress/dist @@ -134,8 +125,6 @@ out # Serverless Webpack directories .webpack/ -# Optional stylelint cache - # SvelteKit build / generate output .svelte-kit @@ -205,14 +194,6 @@ fabric.properties # Android studio 3.1+ serialized cache file .idea/caches/build_file_checksums.ser -### Intellij Patch ### -# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 - -# *.iml -# modules.xml -# .idea/misc.xml -# *.ipr - # Sonarlint plugin # https://plugins.jetbrains.com/plugin/7973-sonarlint .idea/**/sonarlint/ diff --git a/CHANGELOG b/CHANGELOG index 18d9a69..bdf81be 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,8 @@ +v4.7.0 - xx/04/2025 +- Hide preview link if post is tagged as spoiler +- Improve posts filter via URL +- Update Rollup module bundler (v4.39.0) + v4.6.0 - 07/03/2025 - Show preview link content in boosted posts - Fix spoiler text switch button diff --git a/dist/mastodon-timeline.esm.js b/dist/mastodon-timeline.esm.js index 26fa9ff..3cddeee 100644 --- a/dist/mastodon-timeline.esm.js +++ b/dist/mastodon-timeline.esm.js @@ -1,8 +1,8 @@ /** * Mastodon embed timeline * @author idotj - * @version 4.6.0 + * @version 4.7.0 * @url https://gitlab.com/idotj/mastodon-embed-timeline * @license GNU AGPLv3 */ -class t{constructor(t={}){this.defaultSettings={mtContainerId:"mt-container",instanceUrl:"https://mastodon.social",timelineType:"local",userId:"",profileName:"",hashtagName:"",spinnerClass:"mt-loading-spinner",defaultTheme:"auto",maxNbPostFetch:"20",maxNbPostShow:"20",dateFormatLocale:"en-GB",dateFormatOptions:{day:"2-digit",month:"short",year:"numeric"},hideUnlisted:!1,hideReblog:!1,hideReplies:!1,hidePinnedPosts:!1,hideUserAccount:!1,txtMaxLines:"",filterByLanguage:"",btnShowMore:"SHOW MORE",btnShowLess:"SHOW LESS",markdownBlockquote:!1,hideEmojos:!1,btnShowContent:"SHOW CONTENT",hideVideoPreview:!1,btnPlayVideoTxt:"Load and play video",hidePreviewLink:!1,previewMaxLines:"",hideCounterBar:!1,disableCarousel:!1,carouselCloseTxt:"Close carousel",carouselPrevTxt:"Previous media item",carouselNextTxt:"Next media item",btnSeeMore:"See more posts at Mastodon",btnReload:"Refresh",insistSearchContainer:!1,insistSearchContainerTime:"3000"},this.mtSettings={...this.defaultSettings,...t},this.#t(),this.linkHeader={},this.mtContainerNode="",this.mtBodyNode="",this.fetchedData={},this.#e((()=>{this.#i()}))}#t(){Number(this.mtSettings.maxNbPostShow)>Number(this.mtSettings.maxNbPostFetch)&&(console.error(`Please check your settings! The maximum number of posts to show is bigger than the maximum number of posts to fetch. Changing the value of "maxNbPostFetch" to: ${this.mtSettings.maxNbPostShow}`),this.mtSettings.maxNbPostFetch=this.mtSettings.maxNbPostShow)}#e(t){"undefined"!=typeof document&&"complete"===document.readyState?t():"undefined"!=typeof document&&"complete"!==document.readyState&&document.addEventListener("DOMContentLoaded",t())}#i(){const t=()=>{this.mtContainerNode=document.getElementById(this.mtSettings.mtContainerId),this.mtBodyNode=this.mtContainerNode.getElementsByClassName("mt-body")[0],this.#s(),this.#a("newTimeline")};if(this.mtSettings.insistSearchContainer){const e=performance.now(),i=()=>{if(document.getElementById(this.mtSettings.mtContainerId))t();else{performance.now()-e container with id: "${this.mtSettings.mtContainerId}" after several attempts for ${this.mtSettings.insistSearchContainerTime/1e3} seconds`)}};i()}else document.getElementById(this.mtSettings.mtContainerId)?t():console.error(`Impossible to find the
container with id: "${this.mtSettings.mtContainerId}". Please try to add the option 'insistSearchContainer: true' when initializing the script`)}mtUpdate(){this.#e((()=>{this.mtBodyNode.replaceChildren(),this.mtBodyNode.insertAdjacentHTML("afterbegin",'
'),this.#a("updateTimeline")}))}mtColorTheme(t){this.#e((()=>{this.mtContainerNode.setAttribute("data-theme",t)}))}#s(){if("auto"===this.mtSettings.defaultTheme){let t=window.matchMedia("(prefers-color-scheme: dark)");t.matches?this.mtColorTheme("dark"):this.mtColorTheme("light"),t.addEventListener("change",(t=>{t.matches?this.mtColorTheme("dark"):this.mtColorTheme("light")}))}else this.mtColorTheme(this.mtSettings.defaultTheme)}#o(){return new Promise(((t,e)=>{const i=this.mtSettings.instanceUrl?`${this.mtSettings.instanceUrl}/api/v1/`:this.#n("Please check your instanceUrl value","⚠️"),s=this.#r(i),a=Object.entries(s).map((([t,i])=>{const s="timeline"===t;return this.#l(i,s).then((e=>({[t]:e}))).catch((s=>(e(new Error(`Something went wrong fetching data from: ${i}`)),this.#n(s.message),{[t]:[]})))}));Promise.all(a).then((async e=>{if(this.fetchedData=e.reduce(((t,e)=>({...t,...e})),{}),!this.mtSettings.hidePinnedPosts&&void 0!==this.fetchedData.pinned?.length&&0!==this.fetchedData.pinned.length){const t=this.fetchedData.pinned.map((t=>({...t,pinned:!0})));this.fetchedData.timeline=[...t,...this.fetchedData.timeline]}if(this.#d())t();else{do{await this.#m()}while(!this.#d()&&this.linkHeader.next);t()}}))}))}#r(t){const{timelineType:e,userId:i,hashtagName:s,maxNbPostFetch:a,hidePinnedPosts:o,hideEmojos:n}=this.mtSettings,r={};switch(e){case"profile":if(!i){this.#n("Please check your userId value","⚠️");break}r.timeline=`${t}accounts/${i}/statuses?limit=${a}`,o||(r.pinned=`${t}accounts/${i}/statuses?pinned=true`);break;case"hashtag":if(!s){this.#n("Please check your hashtagName value","⚠️");break}r.timeline=`${t}timelines/tag/${s}?limit=${a}`;break;case"local":r.timeline=`${t}timelines/public?local=true&limit=${a}`;break;default:this.#n("Please check your timelineType value","⚠️")}return n||(r.emojos=`${t}custom_emojis`),r}async#l(t,e=!1){const i=await fetch(t);if(!i.ok)throw new Error(`\n Failed to fetch the following Url:
${t}
Error status: ${i.status}
Error message: ${i.statusText}\n `);const s=await i.json();return e&&i.headers.get("Link")&&(this.linkHeader=this.#h(i.headers.get("Link"))),s}#d(){return this.fetchedData.timeline.length>=Number(this.mtSettings.maxNbPostFetch)}#m(){return new Promise((t=>{this.linkHeader.next?this.#l(this.linkHeader.next,!0).then((e=>{this.fetchedData.timeline=[...this.fetchedData.timeline,...e],t()})):t()}))}#h(t){const e=t.split(", ").map((t=>t.split("; "))).map((t=>[t[1].replace(/"/g,"").replace("rel=",""),t[0].slice(1,-1)]));return Object.fromEntries(e)}async#a(t){await this.#o();const{hideUnlisted:e,hideReblog:i,hideReplies:s,maxNbPostShow:a,filterByLanguage:o}=this.mtSettings,n=this.fetchedData.timeline;this.mtBodyNode.replaceChildren();if(n.filter((t=>{const a="public"===t.visibility||!e&&"unlisted"===t.visibility,n=i&&t.reblog,r=s&&t.in_reply_to_id,l=t.language||(t.reblog?t.reblog.language:null);return a&&!n&&!r&&(""===o||l===o)})).forEach(((t,e)=>{e${n?.length||0} posts have been fetched from the server
This may be due to an incorrect configuration with the parameters or with the filters applied (to hide certains type of posts)`;this.#n(t,"📭")}}#g(){"0"!==this.mtSettings.txtMaxLines&&0!==this.mtSettings.txtMaxLines.length&&this.mtBodyNode.parentNode.style.setProperty("--mt-txt-max-lines",this.mtSettings.txtMaxLines),"0"!==this.mtSettings.previewMaxLines&&0!==this.mtSettings.previewMaxLines.length&&this.mtBodyNode.parentNode.style.setProperty("--mt-preview-max-lines",this.mtSettings.previewMaxLines)}#u(t){const e=this.mtBodyNode.getElementsByTagName("article");for(let i=0;i
'+this.#f(h)+' avatar
'+(i?'
'+this.#f(t.account.username)+' avatar
':"")+"
",u='
'+(!this.mtSettings.hideEmojos&&c?this.#x(c,p):c||h)+""+(this.mtSettings.hideUserAccount?"":'
")+"
",v=this.#y(o),b='
'+(t.pinned?'':"")+'"+(t.edited_at?" *":"")+"
",w="0"!==this.mtSettings.txtMaxLines&&this.mtSettings.txtMaxLines.length?" truncate":"";let f="";const x=s.spoiler_text?s.spoiler_text:s.content,y='
'+this.#S(s.content)+"
";x&&(f='
'+this.#S(x)+(s.spoiler_text?y:"")+"
");const S=[...t.media_attachments,...t.reblog?.media_attachments||[]].map((t=>this.#L(t,s.sensitive))).join("");return'
'+g+u+b+"
"+f+(S?`
${S}
`:"")+(this.mtSettings.hidePreviewLink||!t.card&&!t.reblog?.card?"":this.#T(i?t.reblog.card:t.card))+(t.poll?'
    '+t.poll.options.map((function(t){return"
  • "+t.title+"
  • "})).join("")+"
":"")+(this.mtSettings.hideCounterBar?"":'
'+this.#N("replies",n)+this.#N("reblog",r)+this.#N("favorites",l)+"
")+"
"}#N(t,e){return`
${{replies:'',reblog:'',favorites:''}[t]}${e}
`}#M(t,e){function i(t,e){let i=e.replace(/\s+/g,"").toLowerCase();return!(!["src","href","xlink:href"].includes(t)||!i.includes("javascript:")&&!i.includes("data:"))||(!!t.startsWith("on")||void 0)}function s(t){let e=t.attributes;for(let{name:s,value:a}of e)i(s,a)&&t.removeAttribute(s)}let a=(new DOMParser).parseFromString(t,"text/html").body||document.createElement("body");return function(t){let e=t.querySelectorAll("script");for(let t of e)t.remove()}(a),function t(e){let i=e.children;for(let e of i)s(e),t(e)}(a),e?a.childNodes:a.innerHTML}#S(t){let e=t;return e=this.#M(e,!1),e=this.#C(e),this.mtSettings.hideEmojos||(e=this.#x(e,this.fetchedData.emojos)),this.mtSettings.markdownBlockquote&&(e=this.#k(e,"

>","

","

","

")),e}#C(t){let e=t.replaceAll('rel="tag"','rel="tag" target="_blank"');return e=e.replaceAll('class="u-url mention"','class="u-url mention" target="_blank"'),e}#k(t,e,i,s,a){if(t.includes(e)){const o=new RegExp(e+"(.*?)"+i,"gi");return t.replace(o,s+"$1"+a)}return t}#f(t){return(t??"").replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}#x(t,e){if(t.includes(":")){for(const i of e){const e=new RegExp(`\\:${i.shortcode}\\:`,"g");t=t.replace(e,`Emoji ${i.shortcode}`)}return t}return t}#y(t){const e=new Date(t);return new Intl.DateTimeFormat(this.mtSettings.dateFormatLocale,this.mtSettings.dateFormatOptions).format(e)}#L(t,e=!1){const{type:i,url:s,preview_url:a,description:o,meta:n}=t,{original:r,small:l}=n,{spinnerClass:d,btnShowContent:m,btnPlayVideoTxt:h,hideVideoPreview:c}=this.mtSettings,p='",g=' class="mt-post-media '+(e?"mt-post-media-spoiler ":"")+(d||"")+'" data-media-type="'+i+'" data-media-url-hd="'+s+'"'+(o?' data-media-alt-txt="'+this.#f(o)+'"':"")+' data-media-width-hd="'+r.width+'" data-media-height-hd="'+r.height+'" style="padding-top: calc(100%/'+l?.aspect+')">';return"image"===i?"
':"audio"===i?'
'+(e?p:"")+''+(a?''+(o?this.#f(o):':"")+"
":"video"===i||"gifv"===i?c?"':"':""}#P(t,e){let i=document.createElement("dialog");i.id=t,i.classList.add("mt-dialog"),i.dataset.theme=this.mtContainerNode.getAttribute("data-theme"),i.innerHTML=e,document.body.prepend(i),i.showModal(),i.addEventListener("close",(()=>{document.body.removeChild(i)}))}#E(t){const e=Array.from(t.target.parentNode.parentNode.children).filter((t=>!t.classList.contains("mt-post-media-spoiler"))),i=e.indexOf(t.target.parentNode)+1;let s=[];e.forEach(((t,e)=>{let i="";i="gifv"===t.getAttribute("data-media-type")||"video"===t.getAttribute("data-media-type")?`\n \n `:`\n ${t.getAttribute(\n `;const a=`\n \n `;s.push(a)}));const a=`\n \n\n \n\n \n\n \n `;this.#P("mt-carousel",a),s.length>=2&&this.#$(e.length,i)}#$(t,e){let i=e;const s=document.getElementById("mt-carousel-scroll");let a=0,o=!1;const n=document.getElementById("mt-carousel-prev"),r=document.getElementById("mt-carousel-next"),l=(t,e="smooth")=>{document.getElementById("mt-carousel-"+t).scrollIntoView({behavior:e})};l(i,"instant");const d=()=>{clearTimeout(a),a=setTimeout((()=>{o&&(i=(()=>{const t=(s.scrollLeft+s.clientWidth)/s.clientWidth;return Math.round(t+Number.EPSILON)})(),m()),o=!0}),60)};s.addEventListener("scroll",d);const m=()=>{n.hidden=1===i,r.hidden=i===t},h=e=>{const s=e.target.closest("button")?.id;"mt-carousel-next"===s?(o=!1,++i,i>t&&(i=t),l(i),m()):"mt-carousel-prev"===s&&(o=!1,--i,i<1&&(i=1),l(i),m()),"mt-carousel-close"===s&&p()};document.addEventListener("click",h);const c=t=>{"Escape"!==t.key&&27!==t.keyCode||p()};document.addEventListener("keydown",c);const p=()=>{s.removeEventListener("scroll",d),document.removeEventListener("click",h),document.removeEventListener("keydown",c)}}#B(t){const e=t.target.closest("[data-media-type]"),i=e.dataset.mediaUrlHd;e.replaceChildren(),e.innerHTML=``}#A(t){const e=t.target,i=e.nextSibling,s="true"===e.getAttribute("aria-expanded");i.classList.toggle("spoiler-txt-hidden",s),i.classList.toggle("spoiler-txt-visible",!s),e.setAttribute("aria-expanded",!s),e.textContent=s?this.mtSettings.btnShowMore:this.mtSettings.btnShowLess}#H(t){const e=t.target;e.parentNode.classList.toggle("mt-post-media-spoiler",!e.classList.contains("mt-btn-spoiler-media-show"))}#T(t){const{url:e,image:i,image_description:s,provider_name:a,title:o,description:n,author_name:r}=t,{previewMaxLines:l,spinnerClass:d}=this.mtSettings;let m="";return"0"!==l&&n&&(m=''+this.#q(n)+""),''+(i?'
'+this.#f(s)+'
':'
📄
')+'
'+(a?''+this.#q(a)+"":"")+''+o+""+m+(r?''+this.#q(r)+"":"")+"
"}#q(t){return(new DOMParser).parseFromString(t,"text/html").body.textContent}#b(){const{btnSeeMore:t,btnReload:e,timelineType:i,profileName:s,hashtagName:a,instanceUrl:o}=this.mtSettings;let n="",r="";if(t){let e="";switch(i){case"profile":s?e=s:this.#n("Please check your profileName value","⚠️");break;case"hashtag":e="tags/"+a;break;case"local":e="public/local"}n=''+t+""}if(e&&(r='"),this.mtBodyNode.parentNode.insertAdjacentHTML("beforeend",'"),e){const t=this.mtContainerNode.querySelector(".btn-refresh");t&&t.addEventListener("click",(()=>this.mtUpdate()))}}#v(){this.mtBodyNode.addEventListener("click",(t=>{const e=t.target,i=e.localName,s=e.parentNode;("article"==i||"article"==e.offsetParent?.localName||this.mtSettings.disableCarousel&&"image"===s.getAttribute("data-media-type"))&&this.#D(t),e.classList.contains("mt-btn-spoiler-txt")&&this.#A(t),e.classList.contains("mt-btn-spoiler-media")&&this.#H(t),this.mtSettings.disableCarousel||"img"!=i||"image"!==s.getAttribute("data-media-type")&&"audio"!==s.getAttribute("data-media-type")||this.#E(t),("mt-btn-play"==e.className||"svg"==i&&"mt-btn-play"==s.className||"path"==i&&"mt-btn-play"==s.parentNode.className||"img"==i&&("video"===s.getAttribute("data-media-type")||"gifv"===s.getAttribute("data-media-type")))&&this.#B(t)})),this.mtBodyNode.addEventListener("keydown",(t=>{const e=t.target.localName;"Enter"===t.key&&"article"==e&&this.#D(t)}))}#D(t){const e=t.target.closest(".mt-post")?.dataset.location;if(!e)return;const i=t.target.localName;if("a"===i||"span"===i||"button"===i||"bdi"===i||"time"===i)return;const s=t.target.className;if("mt-post-media-spoiler"===s||"mt-post-preview-noImage"===s)return;const a=t.target.parentNode?.className;"mt-post-avatar-image-big"!==a&&"mt-post-avatar-image-small"!==a&&"mt-post-header-user-name"!==a&&"mt-post-preview-image"!==a&&"mt-post-preview"!==a&&window.open(e,"_blank","noopener")}#p(){const t=e=>{e.target.parentNode.classList.remove(this.mtSettings.spinnerClass),e.target.removeEventListener("load",t),e.target.removeEventListener("error",t)};this.mtBodyNode.querySelectorAll(`.${this.mtSettings.spinnerClass} > img`).forEach((e=>{e.addEventListener("load",t),e.addEventListener("error",t)}))}#n(t,e){const i=e||"❌";throw this.mtBodyNode.innerHTML=`\n
\n ${i}\n Oops, something's happened:\n
${t}
\n
`,this.mtBodyNode.setAttribute("role","none"),new Error("Stopping the script due to an error building the timeline.")}}export{t as Init}; +class t{constructor(t={}){this.defaultSettings={mtContainerId:"mt-container",instanceUrl:"https://mastodon.social",timelineType:"local",userId:"",profileName:"",hashtagName:"",spinnerClass:"mt-loading-spinner",defaultTheme:"auto",maxNbPostFetch:"20",maxNbPostShow:"20",dateFormatLocale:"en-GB",dateFormatOptions:{day:"2-digit",month:"short",year:"numeric"},hideUnlisted:!1,hideReblog:!1,hideReplies:!1,hidePinnedPosts:!1,hideUserAccount:!1,txtMaxLines:"",filterByLanguage:"",btnShowMore:"SHOW MORE",btnShowLess:"SHOW LESS",markdownBlockquote:!1,hideEmojos:!1,btnShowContent:"SHOW CONTENT",hideVideoPreview:!1,btnPlayVideoTxt:"Load and play video",hidePreviewLink:!1,previewMaxLines:"",hideCounterBar:!1,disableCarousel:!1,carouselCloseTxt:"Close carousel",carouselPrevTxt:"Previous media item",carouselNextTxt:"Next media item",btnSeeMore:"See more posts at Mastodon",btnReload:"Refresh",insistSearchContainer:!1,insistSearchContainerTime:"3000"},this.mtSettings={...this.defaultSettings,...t},this.#t(),this.linkHeader={},this.mtContainerNode="",this.mtBodyNode="",this.fetchedData={},this.#e((()=>{this.#i()}))}#t(){Number(this.mtSettings.maxNbPostShow)>Number(this.mtSettings.maxNbPostFetch)&&(console.error(`Please check your settings! The maximum number of posts to show is bigger than the maximum number of posts to fetch. Changing the value of "maxNbPostFetch" to: ${this.mtSettings.maxNbPostShow}`),this.mtSettings.maxNbPostFetch=this.mtSettings.maxNbPostShow)}#e(t){"undefined"!=typeof document&&"complete"===document.readyState?t():"undefined"!=typeof document&&"complete"!==document.readyState&&document.addEventListener("DOMContentLoaded",t())}#i(){const t=()=>{this.mtContainerNode=document.getElementById(this.mtSettings.mtContainerId),this.mtBodyNode=this.mtContainerNode.getElementsByClassName("mt-body")[0],this.#s(),this.#a("newTimeline")};if(this.mtSettings.insistSearchContainer){const e=performance.now(),i=()=>{if(document.getElementById(this.mtSettings.mtContainerId))t();else{performance.now()-e container with id: "${this.mtSettings.mtContainerId}" after several attempts for ${this.mtSettings.insistSearchContainerTime/1e3} seconds`)}};i()}else document.getElementById(this.mtSettings.mtContainerId)?t():console.error(`Impossible to find the
container with id: "${this.mtSettings.mtContainerId}". Please try to add the option 'insistSearchContainer: true' when initializing the script`)}mtUpdate(){this.#e((()=>{this.mtBodyNode.replaceChildren(),this.mtBodyNode.insertAdjacentHTML("afterbegin",'
'),this.#a("updateTimeline")}))}mtColorTheme(t){this.#e((()=>{this.mtContainerNode.setAttribute("data-theme",t)}))}#s(){if("auto"===this.mtSettings.defaultTheme){let t=window.matchMedia("(prefers-color-scheme: dark)");t.matches?this.mtColorTheme("dark"):this.mtColorTheme("light"),t.addEventListener("change",(t=>{t.matches?this.mtColorTheme("dark"):this.mtColorTheme("light")}))}else this.mtColorTheme(this.mtSettings.defaultTheme)}#o(){return new Promise(((t,e)=>{const i=this.mtSettings.instanceUrl?`${this.mtSettings.instanceUrl}/api/v1/`:this.#n("Please check your instanceUrl value","⚠️"),s=this.#r(i),a=Object.entries(s).map((([t,i])=>this.#l(i,t).then((e=>({[t]:e}))).catch((i=>(e(new Error("Something went wrong getting the timeline data.")),this.#n(i.message),{[t]:[]})))));Promise.all(a).then((async e=>{if(this.fetchedData=e.reduce(((t,e)=>({...t,...e})),{}),!this.mtSettings.hidePinnedPosts&&void 0!==this.fetchedData.pinned?.length&&0!==this.fetchedData.pinned.length){const t=this.fetchedData.pinned.map((t=>({...t,pinned:!0})));this.fetchedData.timeline=[...t,...this.fetchedData.timeline]}if(this.#d())t();else{do{await this.#m()}while(!this.#d()&&this.linkHeader.next);t()}}))}))}#r(t){const{timelineType:e,userId:i,hashtagName:s,hideReblog:a,hideReplies:o,maxNbPostFetch:n,hidePinnedPosts:r,hideEmojos:l}=this.mtSettings,d={};switch(e){case"profile":if(!i){this.#n("Please check your userId value","⚠️");break}d.timeline=`${t}accounts/${i}/statuses?limit=${n}`,r||(d.pinned=`${t}accounts/${i}/statuses?pinned=true`);break;case"hashtag":if(!s){this.#n("Please check your hashtagName value","⚠️");break}d.timeline=`${t}timelines/tag/${s}?limit=${n}`;break;case"local":d.timeline=`${t}timelines/public?local=true&limit=${n}`;break;default:this.#n("Please check your timelineType value","⚠️")}return a&&(d.timeline+="&exclude_reblogs=true"),o&&(d.timeline+="&exclude_replies=true"),l||(d.emojos=`${t}custom_emojis`),d}async#l(t,e){const i=await fetch(t);if(!i.ok)throw new Error(`\n Failed to fetch the following Url:
${t}
Error status: ${i.status}
Error message: ${i.statusText}\n `);const s=await i.json();return"timeline"===e&&i.headers.get("Link")&&(this.linkHeader=this.#h(i.headers.get("Link"))),s}#d(){return this.fetchedData.timeline.length>=Number(this.mtSettings.maxNbPostFetch)}#m(){return new Promise((t=>{this.linkHeader.next?this.#l(this.linkHeader.next,"timeline").then((e=>{this.fetchedData.timeline=[...this.fetchedData.timeline,...e],t()})).catch((t=>(reject(new Error("Something went wrong fetching more posts.")),this.#n(t.message),{[key]:[]}))):t()}))}#h(t){const e=t.split(", ").map((t=>t.split("; "))).map((t=>[t[1].replace(/"/g,"").replace("rel=",""),t[0].slice(1,-1)]));return Object.fromEntries(e)}async#a(t){await this.#o();const{hideUnlisted:e,maxNbPostShow:i,filterByLanguage:s}=this.mtSettings,a=this.fetchedData.timeline;this.mtBodyNode.replaceChildren();if(a.filter((t=>{const i="public"===t.visibility||!e&&"unlisted"===t.visibility,a=t.language||(t.reblog?t.reblog.language:null);return i&&(""===s||a===s)})).forEach(((t,e)=>{e${a?.length||0} posts have been fetched from the server
This may be due to an incorrect configuration with the parameters or with the filters applied (to hide certains type of posts)`;this.#n(t,"📭")}}#g(){"0"!==this.mtSettings.txtMaxLines&&0!==this.mtSettings.txtMaxLines.length&&this.mtBodyNode.parentNode.style.setProperty("--mt-txt-max-lines",this.mtSettings.txtMaxLines),"0"!==this.mtSettings.previewMaxLines&&0!==this.mtSettings.previewMaxLines.length&&this.mtBodyNode.parentNode.style.setProperty("--mt-preview-max-lines",this.mtSettings.previewMaxLines)}#u(t){const e=this.mtBodyNode.getElementsByTagName("article");for(let i=0;i
'+this.#f(h)+' avatar
'+(i?'
'+this.#f(t.account.username)+' avatar
':"")+"
",u='
'+(!this.mtSettings.hideEmojos&&c?this.#x(c,p):c||h)+""+(this.mtSettings.hideUserAccount?"":'
")+"
",v=this.#S(o),b='
'+(t.pinned?'':"")+'"+(t.edited_at?" *":"")+"
",w=this.mtSettings.hidePreviewLink||!t.card&&!t.reblog?.card?"":this.#y(i?t.reblog.card:t.card),f="0"!==this.mtSettings.txtMaxLines&&this.mtSettings.txtMaxLines.length?" truncate":"";let x="";const S=s.spoiler_text?s.spoiler_text:s.content,y='
'+this.#L(s.content)+w+"
";S&&(x='
'+this.#L(S)+(s.spoiler_text?y:"")+"
");const L=[...t.media_attachments,...t.reblog?.media_attachments||[]].map((t=>this.#T(t,s.sensitive))).join(""),T=L?`
${L}
`:"",N=t.poll?'
    '+t.poll.options.map((function(t){return"
  • "+t.title+"
  • "})).join("")+"
":"",M=this.mtSettings.hideCounterBar?"":'
'+this.#N("replies",n)+this.#N("reblog",r)+this.#N("favorites",l)+"
";return'
'+g+u+b+"
"+x+T+N+(s.spoiler_text?"":w)+M+"
"}#N(t,e){return`
${{replies:'',reblog:'',favorites:''}[t]}${e}
`}#M(t,e){function i(t,e){let i=e.replace(/\s+/g,"").toLowerCase();return!(!["src","href","xlink:href"].includes(t)||!i.includes("javascript:")&&!i.includes("data:"))||(!!t.startsWith("on")||void 0)}function s(t){let e=t.attributes;for(let{name:s,value:a}of e)i(s,a)&&t.removeAttribute(s)}let a=(new DOMParser).parseFromString(t,"text/html").body||document.createElement("body");return function(t){let e=t.querySelectorAll("script");for(let t of e)t.remove()}(a),function t(e){let i=e.children;for(let e of i)s(e),t(e)}(a),e?a.childNodes:a.innerHTML}#L(t){let e=t;return e=this.#M(e,!1),e=this.#k(e),this.mtSettings.hideEmojos||(e=this.#x(e,this.fetchedData.emojos)),this.mtSettings.markdownBlockquote&&(e=this.#C(e,"

>","

","

","

")),e}#k(t){let e=t.replaceAll('rel="tag"','rel="tag" target="_blank"');return e=e.replaceAll('class="u-url mention"','class="u-url mention" target="_blank"'),e}#C(t,e,i,s,a){if(t.includes(e)){const o=new RegExp(e+"(.*?)"+i,"gi");return t.replace(o,s+"$1"+a)}return t}#f(t){return(t??"").replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}#x(t,e){if(t.includes(":")){for(const i of e){const e=new RegExp(`\\:${i.shortcode}\\:`,"g");t=t.replace(e,`Emoji ${i.shortcode}`)}return t}return t}#S(t){const e=new Date(t);return new Intl.DateTimeFormat(this.mtSettings.dateFormatLocale,this.mtSettings.dateFormatOptions).format(e)}#T(t,e=!1){const{type:i,url:s,preview_url:a,description:o,meta:n}=t,{original:r,small:l}=n,{spinnerClass:d,btnShowContent:m,btnPlayVideoTxt:h,hideVideoPreview:c}=this.mtSettings,p='",g=' class="mt-post-media '+(e?"mt-post-media-spoiler ":"")+(d||"")+'" data-media-type="'+i+'" data-media-url-hd="'+s+'"'+(o?' data-media-alt-txt="'+this.#f(o)+'"':"")+' data-media-width-hd="'+r.width+'" data-media-height-hd="'+r.height+'" style="padding-top: calc(100%/'+l?.aspect+')">';return"image"===i?"
':"audio"===i?'
'+(e?p:"")+''+(a?''+(o?this.#f(o):':"")+"
":"video"===i||"gifv"===i?c?"':"':""}#P(t,e){let i=document.createElement("dialog");i.id=t,i.classList.add("mt-dialog"),i.dataset.theme=this.mtContainerNode.getAttribute("data-theme"),i.innerHTML=e,document.body.prepend(i),i.showModal(),i.addEventListener("close",(()=>{document.body.removeChild(i)}))}#E(t){const e=Array.from(t.target.parentNode.parentNode.children).filter((t=>!t.classList.contains("mt-post-media-spoiler"))),i=e.indexOf(t.target.parentNode)+1;let s=[];e.forEach(((t,e)=>{let i="";i="gifv"===t.getAttribute("data-media-type")||"video"===t.getAttribute("data-media-type")?`\n \n `:`\n ${t.getAttribute(\n `;const a=`\n \n `;s.push(a)}));const a=`\n \n\n \n\n \n\n \n `;this.#P("mt-carousel",a),s.length>=2&&this.#$(e.length,i)}#$(t,e){let i=e;const s=document.getElementById("mt-carousel-scroll");let a=0,o=!1;const n=document.getElementById("mt-carousel-prev"),r=document.getElementById("mt-carousel-next"),l=(t,e="smooth")=>{document.getElementById("mt-carousel-"+t).scrollIntoView({behavior:e})};l(i,"instant");const d=()=>{clearTimeout(a),a=setTimeout((()=>{o&&(i=(()=>{const t=(s.scrollLeft+s.clientWidth)/s.clientWidth;return Math.round(t+Number.EPSILON)})(),m()),o=!0}),60)};s.addEventListener("scroll",d);const m=()=>{n.hidden=1===i,r.hidden=i===t},h=e=>{const s=e.target.closest("button")?.id;"mt-carousel-next"===s?(o=!1,++i,i>t&&(i=t),l(i),m()):"mt-carousel-prev"===s&&(o=!1,--i,i<1&&(i=1),l(i),m()),"mt-carousel-close"===s&&p()};document.addEventListener("click",h);const c=t=>{"Escape"!==t.key&&27!==t.keyCode||p()};document.addEventListener("keydown",c);const p=()=>{s.removeEventListener("scroll",d),document.removeEventListener("click",h),document.removeEventListener("keydown",c)}}#B(t){const e=t.target.closest("[data-media-type]"),i=e.dataset.mediaUrlHd;e.replaceChildren(),e.innerHTML=``}#A(t){const e=t.target,i=e.nextSibling,s="true"===e.getAttribute("aria-expanded");i.classList.toggle("spoiler-txt-hidden",s),i.classList.toggle("spoiler-txt-visible",!s),e.setAttribute("aria-expanded",!s),e.textContent=s?this.mtSettings.btnShowMore:this.mtSettings.btnShowLess}#H(t){const e=t.target;e.parentNode.classList.toggle("mt-post-media-spoiler",!e.classList.contains("mt-btn-spoiler-media-show"))}#y(t){const{url:e,image:i,image_description:s,provider_name:a,title:o,description:n,author_name:r}=t,{previewMaxLines:l,spinnerClass:d}=this.mtSettings;let m="";return"0"!==l&&n&&(m=''+this.#q(n)+""),''+(i?'
'+this.#f(s)+'
':'
📄
')+'
'+(a?''+this.#q(a)+"":"")+''+o+""+m+(r?''+this.#q(r)+"":"")+"
"}#q(t){return(new DOMParser).parseFromString(t,"text/html").body.textContent}#b(){const{btnSeeMore:t,btnReload:e,timelineType:i,profileName:s,hashtagName:a,instanceUrl:o}=this.mtSettings;let n="",r="";if(t){let e="";switch(i){case"profile":s?e=s:this.#n("Please check your profileName value","⚠️");break;case"hashtag":e="tags/"+a;break;case"local":e="public/local"}n=''+t+""}if(e&&(r='"),this.mtBodyNode.parentNode.insertAdjacentHTML("beforeend",'"),e){const t=this.mtContainerNode.querySelector(".btn-refresh");t&&t.addEventListener("click",(()=>this.mtUpdate()))}}#v(){this.mtBodyNode.addEventListener("click",(t=>{const e=t.target,i=e.localName,s=e.parentNode;("article"==i||"article"==e.offsetParent?.localName||this.mtSettings.disableCarousel&&"image"===s.getAttribute("data-media-type"))&&this.#D(t),e.classList.contains("mt-btn-spoiler-txt")&&this.#A(t),e.classList.contains("mt-btn-spoiler-media")&&this.#H(t),this.mtSettings.disableCarousel||"img"!=i||"image"!==s.getAttribute("data-media-type")&&"audio"!==s.getAttribute("data-media-type")||this.#E(t),("mt-btn-play"==e.className||"svg"==i&&"mt-btn-play"==s.className||"path"==i&&"mt-btn-play"==s.parentNode.className||"img"==i&&("video"===s.getAttribute("data-media-type")||"gifv"===s.getAttribute("data-media-type")))&&this.#B(t)})),this.mtBodyNode.addEventListener("keydown",(t=>{const e=t.target.localName;"Enter"===t.key&&"article"==e&&this.#D(t)}))}#D(t){const e=t.target.closest(".mt-post")?.dataset.location;if(!e)return;const i=t.target.localName;if("a"===i||"span"===i||"button"===i||"bdi"===i||"time"===i)return;const s=t.target.className;if("mt-post-media-spoiler"===s||"mt-post-preview-noImage"===s)return;const a=t.target.parentNode?.className;"mt-post-avatar-image-big"!==a&&"mt-post-avatar-image-small"!==a&&"mt-post-header-user-name"!==a&&"mt-post-preview-image"!==a&&"mt-post-preview"!==a&&window.open(e,"_blank","noopener")}#p(){const t=e=>{e.target.parentNode.classList.remove(this.mtSettings.spinnerClass),e.target.removeEventListener("load",t),e.target.removeEventListener("error",t)};this.mtBodyNode.querySelectorAll(`.${this.mtSettings.spinnerClass} > img`).forEach((e=>{e.addEventListener("load",t),e.addEventListener("error",t)}))}#n(t,e){const i=e||"❌";throw this.mtBodyNode.innerHTML=`\n
\n ${i}\n Oops, something's happened:\n
${t}
\n
`,this.mtBodyNode.setAttribute("role","none"),new Error("Stopping the script due to an error building the timeline.")}}export{t as Init}; diff --git a/dist/mastodon-timeline.umd.js b/dist/mastodon-timeline.umd.js index a6aed99..953d8ff 100644 --- a/dist/mastodon-timeline.umd.js +++ b/dist/mastodon-timeline.umd.js @@ -2,7 +2,7 @@ /** * Mastodon embed timeline * @author idotj - * @version 4.6.0 + * @version 4.7.0 * @url https://gitlab.com/idotj/mastodon-embed-timeline * @license GNU AGPLv3 - */t.Init=class{constructor(t={}){this.defaultSettings={mtContainerId:"mt-container",instanceUrl:"https://mastodon.social",timelineType:"local",userId:"",profileName:"",hashtagName:"",spinnerClass:"mt-loading-spinner",defaultTheme:"auto",maxNbPostFetch:"20",maxNbPostShow:"20",dateFormatLocale:"en-GB",dateFormatOptions:{day:"2-digit",month:"short",year:"numeric"},hideUnlisted:!1,hideReblog:!1,hideReplies:!1,hidePinnedPosts:!1,hideUserAccount:!1,txtMaxLines:"",filterByLanguage:"",btnShowMore:"SHOW MORE",btnShowLess:"SHOW LESS",markdownBlockquote:!1,hideEmojos:!1,btnShowContent:"SHOW CONTENT",hideVideoPreview:!1,btnPlayVideoTxt:"Load and play video",hidePreviewLink:!1,previewMaxLines:"",hideCounterBar:!1,disableCarousel:!1,carouselCloseTxt:"Close carousel",carouselPrevTxt:"Previous media item",carouselNextTxt:"Next media item",btnSeeMore:"See more posts at Mastodon",btnReload:"Refresh",insistSearchContainer:!1,insistSearchContainerTime:"3000"},this.mtSettings={...this.defaultSettings,...t},this.#t(),this.linkHeader={},this.mtContainerNode="",this.mtBodyNode="",this.fetchedData={},this.#e((()=>{this.#i()}))}#t(){Number(this.mtSettings.maxNbPostShow)>Number(this.mtSettings.maxNbPostFetch)&&(console.error(`Please check your settings! The maximum number of posts to show is bigger than the maximum number of posts to fetch. Changing the value of "maxNbPostFetch" to: ${this.mtSettings.maxNbPostShow}`),this.mtSettings.maxNbPostFetch=this.mtSettings.maxNbPostShow)}#e(t){"undefined"!=typeof document&&"complete"===document.readyState?t():"undefined"!=typeof document&&"complete"!==document.readyState&&document.addEventListener("DOMContentLoaded",t())}#i(){const t=()=>{this.mtContainerNode=document.getElementById(this.mtSettings.mtContainerId),this.mtBodyNode=this.mtContainerNode.getElementsByClassName("mt-body")[0],this.#s(),this.#a("newTimeline")};if(this.mtSettings.insistSearchContainer){const e=performance.now(),i=()=>{if(document.getElementById(this.mtSettings.mtContainerId))t();else{performance.now()-e container with id: "${this.mtSettings.mtContainerId}" after several attempts for ${this.mtSettings.insistSearchContainerTime/1e3} seconds`)}};i()}else document.getElementById(this.mtSettings.mtContainerId)?t():console.error(`Impossible to find the
container with id: "${this.mtSettings.mtContainerId}". Please try to add the option 'insistSearchContainer: true' when initializing the script`)}mtUpdate(){this.#e((()=>{this.mtBodyNode.replaceChildren(),this.mtBodyNode.insertAdjacentHTML("afterbegin",'
'),this.#a("updateTimeline")}))}mtColorTheme(t){this.#e((()=>{this.mtContainerNode.setAttribute("data-theme",t)}))}#s(){if("auto"===this.mtSettings.defaultTheme){let t=window.matchMedia("(prefers-color-scheme: dark)");t.matches?this.mtColorTheme("dark"):this.mtColorTheme("light"),t.addEventListener("change",(t=>{t.matches?this.mtColorTheme("dark"):this.mtColorTheme("light")}))}else this.mtColorTheme(this.mtSettings.defaultTheme)}#o(){return new Promise(((t,e)=>{const i=this.mtSettings.instanceUrl?`${this.mtSettings.instanceUrl}/api/v1/`:this.#n("Please check your instanceUrl value","⚠️"),s=this.#r(i),a=Object.entries(s).map((([t,i])=>{const s="timeline"===t;return this.#l(i,s).then((e=>({[t]:e}))).catch((s=>(e(new Error(`Something went wrong fetching data from: ${i}`)),this.#n(s.message),{[t]:[]})))}));Promise.all(a).then((async e=>{if(this.fetchedData=e.reduce(((t,e)=>({...t,...e})),{}),!this.mtSettings.hidePinnedPosts&&void 0!==this.fetchedData.pinned?.length&&0!==this.fetchedData.pinned.length){const t=this.fetchedData.pinned.map((t=>({...t,pinned:!0})));this.fetchedData.timeline=[...t,...this.fetchedData.timeline]}if(this.#d())t();else{do{await this.#m()}while(!this.#d()&&this.linkHeader.next);t()}}))}))}#r(t){const{timelineType:e,userId:i,hashtagName:s,maxNbPostFetch:a,hidePinnedPosts:o,hideEmojos:n}=this.mtSettings,r={};switch(e){case"profile":if(!i){this.#n("Please check your userId value","⚠️");break}r.timeline=`${t}accounts/${i}/statuses?limit=${a}`,o||(r.pinned=`${t}accounts/${i}/statuses?pinned=true`);break;case"hashtag":if(!s){this.#n("Please check your hashtagName value","⚠️");break}r.timeline=`${t}timelines/tag/${s}?limit=${a}`;break;case"local":r.timeline=`${t}timelines/public?local=true&limit=${a}`;break;default:this.#n("Please check your timelineType value","⚠️")}return n||(r.emojos=`${t}custom_emojis`),r}async#l(t,e=!1){const i=await fetch(t);if(!i.ok)throw new Error(`\n Failed to fetch the following Url:
${t}
Error status: ${i.status}
Error message: ${i.statusText}\n `);const s=await i.json();return e&&i.headers.get("Link")&&(this.linkHeader=this.#h(i.headers.get("Link"))),s}#d(){return this.fetchedData.timeline.length>=Number(this.mtSettings.maxNbPostFetch)}#m(){return new Promise((t=>{this.linkHeader.next?this.#l(this.linkHeader.next,!0).then((e=>{this.fetchedData.timeline=[...this.fetchedData.timeline,...e],t()})):t()}))}#h(t){const e=t.split(", ").map((t=>t.split("; "))).map((t=>[t[1].replace(/"/g,"").replace("rel=",""),t[0].slice(1,-1)]));return Object.fromEntries(e)}async#a(t){await this.#o();const{hideUnlisted:e,hideReblog:i,hideReplies:s,maxNbPostShow:a,filterByLanguage:o}=this.mtSettings,n=this.fetchedData.timeline;this.mtBodyNode.replaceChildren();if(n.filter((t=>{const a="public"===t.visibility||!e&&"unlisted"===t.visibility,n=i&&t.reblog,r=s&&t.in_reply_to_id,l=t.language||(t.reblog?t.reblog.language:null);return a&&!n&&!r&&(""===o||l===o)})).forEach(((t,e)=>{e${n?.length||0} posts have been fetched from the server
This may be due to an incorrect configuration with the parameters or with the filters applied (to hide certains type of posts)`;this.#n(t,"📭")}}#g(){"0"!==this.mtSettings.txtMaxLines&&0!==this.mtSettings.txtMaxLines.length&&this.mtBodyNode.parentNode.style.setProperty("--mt-txt-max-lines",this.mtSettings.txtMaxLines),"0"!==this.mtSettings.previewMaxLines&&0!==this.mtSettings.previewMaxLines.length&&this.mtBodyNode.parentNode.style.setProperty("--mt-preview-max-lines",this.mtSettings.previewMaxLines)}#u(t){const e=this.mtBodyNode.getElementsByTagName("article");for(let i=0;i
'+this.#f(h)+' avatar
'+(i?'
'+this.#f(t.account.username)+' avatar
':"")+"
",u='
'+(!this.mtSettings.hideEmojos&&c?this.#x(c,p):c||h)+""+(this.mtSettings.hideUserAccount?"":'
")+"
",v=this.#y(o),b='
'+(t.pinned?'':"")+'"+(t.edited_at?" *":"")+"
",w="0"!==this.mtSettings.txtMaxLines&&this.mtSettings.txtMaxLines.length?" truncate":"";let f="";const x=s.spoiler_text?s.spoiler_text:s.content,y='
'+this.#S(s.content)+"
";x&&(f='
'+this.#S(x)+(s.spoiler_text?y:"")+"
");const S=[...t.media_attachments,...t.reblog?.media_attachments||[]].map((t=>this.#L(t,s.sensitive))).join("");return'
'+g+u+b+"
"+f+(S?`
${S}
`:"")+(this.mtSettings.hidePreviewLink||!t.card&&!t.reblog?.card?"":this.#T(i?t.reblog.card:t.card))+(t.poll?'
    '+t.poll.options.map((function(t){return"
  • "+t.title+"
  • "})).join("")+"
":"")+(this.mtSettings.hideCounterBar?"":'
'+this.#N("replies",n)+this.#N("reblog",r)+this.#N("favorites",l)+"
")+"
"}#N(t,e){return`
${{replies:'',reblog:'',favorites:''}[t]}${e}
`}#M(t,e){function i(t,e){let i=e.replace(/\s+/g,"").toLowerCase();return!(!["src","href","xlink:href"].includes(t)||!i.includes("javascript:")&&!i.includes("data:"))||(!!t.startsWith("on")||void 0)}function s(t){let e=t.attributes;for(let{name:s,value:a}of e)i(s,a)&&t.removeAttribute(s)}let a=(new DOMParser).parseFromString(t,"text/html").body||document.createElement("body");return function(t){let e=t.querySelectorAll("script");for(let t of e)t.remove()}(a),function t(e){let i=e.children;for(let e of i)s(e),t(e)}(a),e?a.childNodes:a.innerHTML}#S(t){let e=t;return e=this.#M(e,!1),e=this.#C(e),this.mtSettings.hideEmojos||(e=this.#x(e,this.fetchedData.emojos)),this.mtSettings.markdownBlockquote&&(e=this.#k(e,"

>","

","

","

")),e}#C(t){let e=t.replaceAll('rel="tag"','rel="tag" target="_blank"');return e=e.replaceAll('class="u-url mention"','class="u-url mention" target="_blank"'),e}#k(t,e,i,s,a){if(t.includes(e)){const o=new RegExp(e+"(.*?)"+i,"gi");return t.replace(o,s+"$1"+a)}return t}#f(t){return(t??"").replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}#x(t,e){if(t.includes(":")){for(const i of e){const e=new RegExp(`\\:${i.shortcode}\\:`,"g");t=t.replace(e,`Emoji ${i.shortcode}`)}return t}return t}#y(t){const e=new Date(t);return new Intl.DateTimeFormat(this.mtSettings.dateFormatLocale,this.mtSettings.dateFormatOptions).format(e)}#L(t,e=!1){const{type:i,url:s,preview_url:a,description:o,meta:n}=t,{original:r,small:l}=n,{spinnerClass:d,btnShowContent:m,btnPlayVideoTxt:h,hideVideoPreview:c}=this.mtSettings,p='",g=' class="mt-post-media '+(e?"mt-post-media-spoiler ":"")+(d||"")+'" data-media-type="'+i+'" data-media-url-hd="'+s+'"'+(o?' data-media-alt-txt="'+this.#f(o)+'"':"")+' data-media-width-hd="'+r.width+'" data-media-height-hd="'+r.height+'" style="padding-top: calc(100%/'+l?.aspect+')">';return"image"===i?"
':"audio"===i?'
'+(e?p:"")+''+(a?''+(o?this.#f(o):':"")+"
":"video"===i||"gifv"===i?c?"':"':""}#P(t,e){let i=document.createElement("dialog");i.id=t,i.classList.add("mt-dialog"),i.dataset.theme=this.mtContainerNode.getAttribute("data-theme"),i.innerHTML=e,document.body.prepend(i),i.showModal(),i.addEventListener("close",(()=>{document.body.removeChild(i)}))}#E(t){const e=Array.from(t.target.parentNode.parentNode.children).filter((t=>!t.classList.contains("mt-post-media-spoiler"))),i=e.indexOf(t.target.parentNode)+1;let s=[];e.forEach(((t,e)=>{let i="";i="gifv"===t.getAttribute("data-media-type")||"video"===t.getAttribute("data-media-type")?`\n \n `:`\n ${t.getAttribute(\n `;const a=`\n \n `;s.push(a)}));const a=`\n \n\n \n\n \n\n \n `;this.#P("mt-carousel",a),s.length>=2&&this.#$(e.length,i)}#$(t,e){let i=e;const s=document.getElementById("mt-carousel-scroll");let a=0,o=!1;const n=document.getElementById("mt-carousel-prev"),r=document.getElementById("mt-carousel-next"),l=(t,e="smooth")=>{document.getElementById("mt-carousel-"+t).scrollIntoView({behavior:e})};l(i,"instant");const d=()=>{clearTimeout(a),a=setTimeout((()=>{o&&(i=(()=>{const t=(s.scrollLeft+s.clientWidth)/s.clientWidth;return Math.round(t+Number.EPSILON)})(),m()),o=!0}),60)};s.addEventListener("scroll",d);const m=()=>{n.hidden=1===i,r.hidden=i===t},h=e=>{const s=e.target.closest("button")?.id;"mt-carousel-next"===s?(o=!1,++i,i>t&&(i=t),l(i),m()):"mt-carousel-prev"===s&&(o=!1,--i,i<1&&(i=1),l(i),m()),"mt-carousel-close"===s&&p()};document.addEventListener("click",h);const c=t=>{"Escape"!==t.key&&27!==t.keyCode||p()};document.addEventListener("keydown",c);const p=()=>{s.removeEventListener("scroll",d),document.removeEventListener("click",h),document.removeEventListener("keydown",c)}}#B(t){const e=t.target.closest("[data-media-type]"),i=e.dataset.mediaUrlHd;e.replaceChildren(),e.innerHTML=``}#A(t){const e=t.target,i=e.nextSibling,s="true"===e.getAttribute("aria-expanded");i.classList.toggle("spoiler-txt-hidden",s),i.classList.toggle("spoiler-txt-visible",!s),e.setAttribute("aria-expanded",!s),e.textContent=s?this.mtSettings.btnShowMore:this.mtSettings.btnShowLess}#H(t){const e=t.target;e.parentNode.classList.toggle("mt-post-media-spoiler",!e.classList.contains("mt-btn-spoiler-media-show"))}#T(t){const{url:e,image:i,image_description:s,provider_name:a,title:o,description:n,author_name:r}=t,{previewMaxLines:l,spinnerClass:d}=this.mtSettings;let m="";return"0"!==l&&n&&(m=''+this.#q(n)+""),''+(i?'
'+this.#f(s)+'
':'
📄
')+'
'+(a?''+this.#q(a)+"":"")+''+o+""+m+(r?''+this.#q(r)+"":"")+"
"}#q(t){return(new DOMParser).parseFromString(t,"text/html").body.textContent}#b(){const{btnSeeMore:t,btnReload:e,timelineType:i,profileName:s,hashtagName:a,instanceUrl:o}=this.mtSettings;let n="",r="";if(t){let e="";switch(i){case"profile":s?e=s:this.#n("Please check your profileName value","⚠️");break;case"hashtag":e="tags/"+a;break;case"local":e="public/local"}n=''+t+""}if(e&&(r='"),this.mtBodyNode.parentNode.insertAdjacentHTML("beforeend",'"),e){const t=this.mtContainerNode.querySelector(".btn-refresh");t&&t.addEventListener("click",(()=>this.mtUpdate()))}}#v(){this.mtBodyNode.addEventListener("click",(t=>{const e=t.target,i=e.localName,s=e.parentNode;("article"==i||"article"==e.offsetParent?.localName||this.mtSettings.disableCarousel&&"image"===s.getAttribute("data-media-type"))&&this.#D(t),e.classList.contains("mt-btn-spoiler-txt")&&this.#A(t),e.classList.contains("mt-btn-spoiler-media")&&this.#H(t),this.mtSettings.disableCarousel||"img"!=i||"image"!==s.getAttribute("data-media-type")&&"audio"!==s.getAttribute("data-media-type")||this.#E(t),("mt-btn-play"==e.className||"svg"==i&&"mt-btn-play"==s.className||"path"==i&&"mt-btn-play"==s.parentNode.className||"img"==i&&("video"===s.getAttribute("data-media-type")||"gifv"===s.getAttribute("data-media-type")))&&this.#B(t)})),this.mtBodyNode.addEventListener("keydown",(t=>{const e=t.target.localName;"Enter"===t.key&&"article"==e&&this.#D(t)}))}#D(t){const e=t.target.closest(".mt-post")?.dataset.location;if(!e)return;const i=t.target.localName;if("a"===i||"span"===i||"button"===i||"bdi"===i||"time"===i)return;const s=t.target.className;if("mt-post-media-spoiler"===s||"mt-post-preview-noImage"===s)return;const a=t.target.parentNode?.className;"mt-post-avatar-image-big"!==a&&"mt-post-avatar-image-small"!==a&&"mt-post-header-user-name"!==a&&"mt-post-preview-image"!==a&&"mt-post-preview"!==a&&window.open(e,"_blank","noopener")}#p(){const t=e=>{e.target.parentNode.classList.remove(this.mtSettings.spinnerClass),e.target.removeEventListener("load",t),e.target.removeEventListener("error",t)};this.mtBodyNode.querySelectorAll(`.${this.mtSettings.spinnerClass} > img`).forEach((e=>{e.addEventListener("load",t),e.addEventListener("error",t)}))}#n(t,e){const i=e||"❌";throw this.mtBodyNode.innerHTML=`\n
\n ${i}\n Oops, something's happened:\n
${t}
\n
`,this.mtBodyNode.setAttribute("role","none"),new Error("Stopping the script due to an error building the timeline.")}}})); + */t.Init=class{constructor(t={}){this.defaultSettings={mtContainerId:"mt-container",instanceUrl:"https://mastodon.social",timelineType:"local",userId:"",profileName:"",hashtagName:"",spinnerClass:"mt-loading-spinner",defaultTheme:"auto",maxNbPostFetch:"20",maxNbPostShow:"20",dateFormatLocale:"en-GB",dateFormatOptions:{day:"2-digit",month:"short",year:"numeric"},hideUnlisted:!1,hideReblog:!1,hideReplies:!1,hidePinnedPosts:!1,hideUserAccount:!1,txtMaxLines:"",filterByLanguage:"",btnShowMore:"SHOW MORE",btnShowLess:"SHOW LESS",markdownBlockquote:!1,hideEmojos:!1,btnShowContent:"SHOW CONTENT",hideVideoPreview:!1,btnPlayVideoTxt:"Load and play video",hidePreviewLink:!1,previewMaxLines:"",hideCounterBar:!1,disableCarousel:!1,carouselCloseTxt:"Close carousel",carouselPrevTxt:"Previous media item",carouselNextTxt:"Next media item",btnSeeMore:"See more posts at Mastodon",btnReload:"Refresh",insistSearchContainer:!1,insistSearchContainerTime:"3000"},this.mtSettings={...this.defaultSettings,...t},this.#t(),this.linkHeader={},this.mtContainerNode="",this.mtBodyNode="",this.fetchedData={},this.#e((()=>{this.#i()}))}#t(){Number(this.mtSettings.maxNbPostShow)>Number(this.mtSettings.maxNbPostFetch)&&(console.error(`Please check your settings! The maximum number of posts to show is bigger than the maximum number of posts to fetch. Changing the value of "maxNbPostFetch" to: ${this.mtSettings.maxNbPostShow}`),this.mtSettings.maxNbPostFetch=this.mtSettings.maxNbPostShow)}#e(t){"undefined"!=typeof document&&"complete"===document.readyState?t():"undefined"!=typeof document&&"complete"!==document.readyState&&document.addEventListener("DOMContentLoaded",t())}#i(){const t=()=>{this.mtContainerNode=document.getElementById(this.mtSettings.mtContainerId),this.mtBodyNode=this.mtContainerNode.getElementsByClassName("mt-body")[0],this.#s(),this.#a("newTimeline")};if(this.mtSettings.insistSearchContainer){const e=performance.now(),i=()=>{if(document.getElementById(this.mtSettings.mtContainerId))t();else{performance.now()-e container with id: "${this.mtSettings.mtContainerId}" after several attempts for ${this.mtSettings.insistSearchContainerTime/1e3} seconds`)}};i()}else document.getElementById(this.mtSettings.mtContainerId)?t():console.error(`Impossible to find the
container with id: "${this.mtSettings.mtContainerId}". Please try to add the option 'insistSearchContainer: true' when initializing the script`)}mtUpdate(){this.#e((()=>{this.mtBodyNode.replaceChildren(),this.mtBodyNode.insertAdjacentHTML("afterbegin",'
'),this.#a("updateTimeline")}))}mtColorTheme(t){this.#e((()=>{this.mtContainerNode.setAttribute("data-theme",t)}))}#s(){if("auto"===this.mtSettings.defaultTheme){let t=window.matchMedia("(prefers-color-scheme: dark)");t.matches?this.mtColorTheme("dark"):this.mtColorTheme("light"),t.addEventListener("change",(t=>{t.matches?this.mtColorTheme("dark"):this.mtColorTheme("light")}))}else this.mtColorTheme(this.mtSettings.defaultTheme)}#o(){return new Promise(((t,e)=>{const i=this.mtSettings.instanceUrl?`${this.mtSettings.instanceUrl}/api/v1/`:this.#n("Please check your instanceUrl value","⚠️"),s=this.#r(i),a=Object.entries(s).map((([t,i])=>this.#l(i,t).then((e=>({[t]:e}))).catch((i=>(e(new Error("Something went wrong getting the timeline data.")),this.#n(i.message),{[t]:[]})))));Promise.all(a).then((async e=>{if(this.fetchedData=e.reduce(((t,e)=>({...t,...e})),{}),!this.mtSettings.hidePinnedPosts&&void 0!==this.fetchedData.pinned?.length&&0!==this.fetchedData.pinned.length){const t=this.fetchedData.pinned.map((t=>({...t,pinned:!0})));this.fetchedData.timeline=[...t,...this.fetchedData.timeline]}if(this.#d())t();else{do{await this.#m()}while(!this.#d()&&this.linkHeader.next);t()}}))}))}#r(t){const{timelineType:e,userId:i,hashtagName:s,hideReblog:a,hideReplies:o,maxNbPostFetch:n,hidePinnedPosts:r,hideEmojos:l}=this.mtSettings,d={};switch(e){case"profile":if(!i){this.#n("Please check your userId value","⚠️");break}d.timeline=`${t}accounts/${i}/statuses?limit=${n}`,r||(d.pinned=`${t}accounts/${i}/statuses?pinned=true`);break;case"hashtag":if(!s){this.#n("Please check your hashtagName value","⚠️");break}d.timeline=`${t}timelines/tag/${s}?limit=${n}`;break;case"local":d.timeline=`${t}timelines/public?local=true&limit=${n}`;break;default:this.#n("Please check your timelineType value","⚠️")}return a&&(d.timeline+="&exclude_reblogs=true"),o&&(d.timeline+="&exclude_replies=true"),l||(d.emojos=`${t}custom_emojis`),d}async#l(t,e){const i=await fetch(t);if(!i.ok)throw new Error(`\n Failed to fetch the following Url:
${t}
Error status: ${i.status}
Error message: ${i.statusText}\n `);const s=await i.json();return"timeline"===e&&i.headers.get("Link")&&(this.linkHeader=this.#h(i.headers.get("Link"))),s}#d(){return this.fetchedData.timeline.length>=Number(this.mtSettings.maxNbPostFetch)}#m(){return new Promise((t=>{this.linkHeader.next?this.#l(this.linkHeader.next,"timeline").then((e=>{this.fetchedData.timeline=[...this.fetchedData.timeline,...e],t()})).catch((t=>(reject(new Error("Something went wrong fetching more posts.")),this.#n(t.message),{[key]:[]}))):t()}))}#h(t){const e=t.split(", ").map((t=>t.split("; "))).map((t=>[t[1].replace(/"/g,"").replace("rel=",""),t[0].slice(1,-1)]));return Object.fromEntries(e)}async#a(t){await this.#o();const{hideUnlisted:e,maxNbPostShow:i,filterByLanguage:s}=this.mtSettings,a=this.fetchedData.timeline;this.mtBodyNode.replaceChildren();if(a.filter((t=>{const i="public"===t.visibility||!e&&"unlisted"===t.visibility,a=t.language||(t.reblog?t.reblog.language:null);return i&&(""===s||a===s)})).forEach(((t,e)=>{e${a?.length||0} posts have been fetched from the server
This may be due to an incorrect configuration with the parameters or with the filters applied (to hide certains type of posts)`;this.#n(t,"📭")}}#g(){"0"!==this.mtSettings.txtMaxLines&&0!==this.mtSettings.txtMaxLines.length&&this.mtBodyNode.parentNode.style.setProperty("--mt-txt-max-lines",this.mtSettings.txtMaxLines),"0"!==this.mtSettings.previewMaxLines&&0!==this.mtSettings.previewMaxLines.length&&this.mtBodyNode.parentNode.style.setProperty("--mt-preview-max-lines",this.mtSettings.previewMaxLines)}#u(t){const e=this.mtBodyNode.getElementsByTagName("article");for(let i=0;i
'+this.#f(h)+' avatar
'+(i?'
'+this.#f(t.account.username)+' avatar
':"")+"
",u='
'+(!this.mtSettings.hideEmojos&&c?this.#x(c,p):c||h)+""+(this.mtSettings.hideUserAccount?"":'
")+"
",v=this.#y(o),b='
'+(t.pinned?'':"")+'"+(t.edited_at?" *":"")+"
",w=this.mtSettings.hidePreviewLink||!t.card&&!t.reblog?.card?"":this.#S(i?t.reblog.card:t.card),f="0"!==this.mtSettings.txtMaxLines&&this.mtSettings.txtMaxLines.length?" truncate":"";let x="";const y=s.spoiler_text?s.spoiler_text:s.content,S='
'+this.#L(s.content)+w+"
";y&&(x='
'+this.#L(y)+(s.spoiler_text?S:"")+"
");const L=[...t.media_attachments,...t.reblog?.media_attachments||[]].map((t=>this.#T(t,s.sensitive))).join(""),T=L?`
${L}
`:"",N=t.poll?'
    '+t.poll.options.map((function(t){return"
  • "+t.title+"
  • "})).join("")+"
":"",M=this.mtSettings.hideCounterBar?"":'
'+this.#N("replies",n)+this.#N("reblog",r)+this.#N("favorites",l)+"
";return'
'+g+u+b+"
"+x+T+N+(s.spoiler_text?"":w)+M+"
"}#N(t,e){return`
${{replies:'',reblog:'',favorites:''}[t]}${e}
`}#M(t,e){function i(t,e){let i=e.replace(/\s+/g,"").toLowerCase();return!(!["src","href","xlink:href"].includes(t)||!i.includes("javascript:")&&!i.includes("data:"))||(!!t.startsWith("on")||void 0)}function s(t){let e=t.attributes;for(let{name:s,value:a}of e)i(s,a)&&t.removeAttribute(s)}let a=(new DOMParser).parseFromString(t,"text/html").body||document.createElement("body");return function(t){let e=t.querySelectorAll("script");for(let t of e)t.remove()}(a),function t(e){let i=e.children;for(let e of i)s(e),t(e)}(a),e?a.childNodes:a.innerHTML}#L(t){let e=t;return e=this.#M(e,!1),e=this.#k(e),this.mtSettings.hideEmojos||(e=this.#x(e,this.fetchedData.emojos)),this.mtSettings.markdownBlockquote&&(e=this.#C(e,"

>","

","

","

")),e}#k(t){let e=t.replaceAll('rel="tag"','rel="tag" target="_blank"');return e=e.replaceAll('class="u-url mention"','class="u-url mention" target="_blank"'),e}#C(t,e,i,s,a){if(t.includes(e)){const o=new RegExp(e+"(.*?)"+i,"gi");return t.replace(o,s+"$1"+a)}return t}#f(t){return(t??"").replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}#x(t,e){if(t.includes(":")){for(const i of e){const e=new RegExp(`\\:${i.shortcode}\\:`,"g");t=t.replace(e,`Emoji ${i.shortcode}`)}return t}return t}#y(t){const e=new Date(t);return new Intl.DateTimeFormat(this.mtSettings.dateFormatLocale,this.mtSettings.dateFormatOptions).format(e)}#T(t,e=!1){const{type:i,url:s,preview_url:a,description:o,meta:n}=t,{original:r,small:l}=n,{spinnerClass:d,btnShowContent:m,btnPlayVideoTxt:h,hideVideoPreview:c}=this.mtSettings,p='",g=' class="mt-post-media '+(e?"mt-post-media-spoiler ":"")+(d||"")+'" data-media-type="'+i+'" data-media-url-hd="'+s+'"'+(o?' data-media-alt-txt="'+this.#f(o)+'"':"")+' data-media-width-hd="'+r.width+'" data-media-height-hd="'+r.height+'" style="padding-top: calc(100%/'+l?.aspect+')">';return"image"===i?"
':"audio"===i?'
'+(e?p:"")+''+(a?''+(o?this.#f(o):':"")+"
":"video"===i||"gifv"===i?c?"':"':""}#P(t,e){let i=document.createElement("dialog");i.id=t,i.classList.add("mt-dialog"),i.dataset.theme=this.mtContainerNode.getAttribute("data-theme"),i.innerHTML=e,document.body.prepend(i),i.showModal(),i.addEventListener("close",(()=>{document.body.removeChild(i)}))}#E(t){const e=Array.from(t.target.parentNode.parentNode.children).filter((t=>!t.classList.contains("mt-post-media-spoiler"))),i=e.indexOf(t.target.parentNode)+1;let s=[];e.forEach(((t,e)=>{let i="";i="gifv"===t.getAttribute("data-media-type")||"video"===t.getAttribute("data-media-type")?`\n \n `:`\n ${t.getAttribute(\n `;const a=`\n \n `;s.push(a)}));const a=`\n \n\n \n\n \n\n \n `;this.#P("mt-carousel",a),s.length>=2&&this.#$(e.length,i)}#$(t,e){let i=e;const s=document.getElementById("mt-carousel-scroll");let a=0,o=!1;const n=document.getElementById("mt-carousel-prev"),r=document.getElementById("mt-carousel-next"),l=(t,e="smooth")=>{document.getElementById("mt-carousel-"+t).scrollIntoView({behavior:e})};l(i,"instant");const d=()=>{clearTimeout(a),a=setTimeout((()=>{o&&(i=(()=>{const t=(s.scrollLeft+s.clientWidth)/s.clientWidth;return Math.round(t+Number.EPSILON)})(),m()),o=!0}),60)};s.addEventListener("scroll",d);const m=()=>{n.hidden=1===i,r.hidden=i===t},h=e=>{const s=e.target.closest("button")?.id;"mt-carousel-next"===s?(o=!1,++i,i>t&&(i=t),l(i),m()):"mt-carousel-prev"===s&&(o=!1,--i,i<1&&(i=1),l(i),m()),"mt-carousel-close"===s&&p()};document.addEventListener("click",h);const c=t=>{"Escape"!==t.key&&27!==t.keyCode||p()};document.addEventListener("keydown",c);const p=()=>{s.removeEventListener("scroll",d),document.removeEventListener("click",h),document.removeEventListener("keydown",c)}}#B(t){const e=t.target.closest("[data-media-type]"),i=e.dataset.mediaUrlHd;e.replaceChildren(),e.innerHTML=``}#A(t){const e=t.target,i=e.nextSibling,s="true"===e.getAttribute("aria-expanded");i.classList.toggle("spoiler-txt-hidden",s),i.classList.toggle("spoiler-txt-visible",!s),e.setAttribute("aria-expanded",!s),e.textContent=s?this.mtSettings.btnShowMore:this.mtSettings.btnShowLess}#H(t){const e=t.target;e.parentNode.classList.toggle("mt-post-media-spoiler",!e.classList.contains("mt-btn-spoiler-media-show"))}#S(t){const{url:e,image:i,image_description:s,provider_name:a,title:o,description:n,author_name:r}=t,{previewMaxLines:l,spinnerClass:d}=this.mtSettings;let m="";return"0"!==l&&n&&(m=''+this.#q(n)+""),''+(i?'
'+this.#f(s)+'
':'
📄
')+'
'+(a?''+this.#q(a)+"":"")+''+o+""+m+(r?''+this.#q(r)+"":"")+"
"}#q(t){return(new DOMParser).parseFromString(t,"text/html").body.textContent}#b(){const{btnSeeMore:t,btnReload:e,timelineType:i,profileName:s,hashtagName:a,instanceUrl:o}=this.mtSettings;let n="",r="";if(t){let e="";switch(i){case"profile":s?e=s:this.#n("Please check your profileName value","⚠️");break;case"hashtag":e="tags/"+a;break;case"local":e="public/local"}n=''+t+""}if(e&&(r='"),this.mtBodyNode.parentNode.insertAdjacentHTML("beforeend",'"),e){const t=this.mtContainerNode.querySelector(".btn-refresh");t&&t.addEventListener("click",(()=>this.mtUpdate()))}}#v(){this.mtBodyNode.addEventListener("click",(t=>{const e=t.target,i=e.localName,s=e.parentNode;("article"==i||"article"==e.offsetParent?.localName||this.mtSettings.disableCarousel&&"image"===s.getAttribute("data-media-type"))&&this.#D(t),e.classList.contains("mt-btn-spoiler-txt")&&this.#A(t),e.classList.contains("mt-btn-spoiler-media")&&this.#H(t),this.mtSettings.disableCarousel||"img"!=i||"image"!==s.getAttribute("data-media-type")&&"audio"!==s.getAttribute("data-media-type")||this.#E(t),("mt-btn-play"==e.className||"svg"==i&&"mt-btn-play"==s.className||"path"==i&&"mt-btn-play"==s.parentNode.className||"img"==i&&("video"===s.getAttribute("data-media-type")||"gifv"===s.getAttribute("data-media-type")))&&this.#B(t)})),this.mtBodyNode.addEventListener("keydown",(t=>{const e=t.target.localName;"Enter"===t.key&&"article"==e&&this.#D(t)}))}#D(t){const e=t.target.closest(".mt-post")?.dataset.location;if(!e)return;const i=t.target.localName;if("a"===i||"span"===i||"button"===i||"bdi"===i||"time"===i)return;const s=t.target.className;if("mt-post-media-spoiler"===s||"mt-post-preview-noImage"===s)return;const a=t.target.parentNode?.className;"mt-post-avatar-image-big"!==a&&"mt-post-avatar-image-small"!==a&&"mt-post-header-user-name"!==a&&"mt-post-preview-image"!==a&&"mt-post-preview"!==a&&window.open(e,"_blank","noopener")}#p(){const t=e=>{e.target.parentNode.classList.remove(this.mtSettings.spinnerClass),e.target.removeEventListener("load",t),e.target.removeEventListener("error",t)};this.mtBodyNode.querySelectorAll(`.${this.mtSettings.spinnerClass} > img`).forEach((e=>{e.addEventListener("load",t),e.addEventListener("error",t)}))}#n(t,e){const i=e||"❌";throw this.mtBodyNode.innerHTML=`\n
\n ${i}\n Oops, something's happened:\n
${t}
\n
`,this.mtBodyNode.setAttribute("role","none"),new Error("Stopping the script due to an error building the timeline.")}}})); diff --git a/docker-compose.yml b/docker-compose.yml index c4c66e3..622bc13 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,23 +1,22 @@ -# This is a docker compose file to demonstrate and test the Mastodon embed timeline widget -# Run this docker CLI from the root repository directory: -# -# $ docker compose up - -version: "3.3" - -services: - lighttpd: - image: jitesoft/lighttpd - ports: - - "8080:80" - - "8443:443" - volumes: - - ./dist:/var/www/dist - - ./examples:/var/www/examples - environment: - - PORT=80 - - SERVER_NAME=mastodon-timeline - - SERVER_ROOT=/var/www - - CONFIG_FILE=/etc/lighttpd/lighttpd.conf - - SKIP_HEALTHCHECK=false - - MAX_FDS=1024 +# This is a docker compose file to demonstrate and test the Mastodon embed timeline widget +# Run this docker CLI from the root repository directory: +# $ docker compose up + +version: "3.3" + +services: + lighttpd: + image: jitesoft/lighttpd + ports: + - "8080:80" + - "8443:443" + volumes: + - ./dist:/var/www/dist + - ./examples:/var/www/examples + environment: + - PORT=80 + - SERVER_NAME=mastodon-timeline + - SERVER_ROOT=/var/www + - CONFIG_FILE=/etc/lighttpd/lighttpd.conf + - SKIP_HEALTHCHECK=false + - MAX_FDS=1024 diff --git a/docs/INSTALLATION.md b/docs/INSTALLATION.md index 3ad6ad9..806afd2 100644 --- a/docs/INSTALLATION.md +++ b/docs/INSTALLATION.md @@ -1,6 +1,7 @@ # 🐘 Mastodon embed timeline - 🛠️ Installation You have three different ways to install it in your project: + - [Download](#download) - [CDN](#cdn) - [Package manager](#package-manager) @@ -45,11 +46,11 @@ This option allows you to start without the need to upload any files on your ser Copy the following CSS and JS links to include them in your project: ```html - + ``` ```html - + ``` ## Package manager diff --git a/docs/SETUP.md b/docs/SETUP.md index c10ce55..f581ec2 100644 --- a/docs/SETUP.md +++ b/docs/SETUP.md @@ -236,4 +236,3 @@ There is a long list of parameters that allows you to quickly customize your tim In the `examples/` folder there is an HTML file `local-timeline-customized.html` that you can use as a referente to see how to customize your timeline by overwriting some CSS styles and using several parameters when initializing the timeline. Also, if you need to change something in the core files (`src/` folder), I recommend you to read the document [CONTRIBUTING.md](https://gitlab.com/idotj/mastodon-embed-timeline/-/blob/master/CONTRIBUTING.md#testing) to see how to compile and test your changes. - diff --git a/package-lock.json b/package-lock.json index 33130c3..5d2645e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,17 @@ { "name": "@idotj/mastodon-embed-timeline", - "version": "4.6.0", + "version": "4.7.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@idotj/mastodon-embed-timeline", - "version": "4.6.0", + "version": "4.7.0", "license": "GNU", "devDependencies": { "@rollup/plugin-terser": "^0.4.4", "clean-css-cli": "^5.6.3", - "rollup": "^4.34.8" + "rollup": "^4.39.0" } }, "node_modules/@jridgewell/gen-mapping": { @@ -95,9 +95,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz", - "integrity": "sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==", + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.39.0.tgz", + "integrity": "sha512-lGVys55Qb00Wvh8DMAocp5kIcaNzEFTmGhfFd88LfaogYTRKrdxgtlO5H6S49v2Nd8R2C6wLOal0qv6/kCkOwA==", "cpu": [ "arm" ], @@ -109,9 +109,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.8.tgz", - "integrity": "sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==", + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.39.0.tgz", + "integrity": "sha512-It9+M1zE31KWfqh/0cJLrrsCPiF72PoJjIChLX+rEcujVRCb4NLQ5QzFkzIZW8Kn8FTbvGQBY5TkKBau3S8cCQ==", "cpu": [ "arm64" ], @@ -123,9 +123,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.8.tgz", - "integrity": "sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==", + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.39.0.tgz", + "integrity": "sha512-lXQnhpFDOKDXiGxsU9/l8UEGGM65comrQuZ+lDcGUx+9YQ9dKpF3rSEGepyeR5AHZ0b5RgiligsBhWZfSSQh8Q==", "cpu": [ "arm64" ], @@ -137,9 +137,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.8.tgz", - "integrity": "sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==", + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.39.0.tgz", + "integrity": "sha512-mKXpNZLvtEbgu6WCkNij7CGycdw9cJi2k9v0noMb++Vab12GZjFgUXD69ilAbBh034Zwn95c2PNSz9xM7KYEAQ==", "cpu": [ "x64" ], @@ -151,9 +151,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.8.tgz", - "integrity": "sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==", + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.39.0.tgz", + "integrity": "sha512-jivRRlh2Lod/KvDZx2zUR+I4iBfHcu2V/BA2vasUtdtTN2Uk3jfcZczLa81ESHZHPHy4ih3T/W5rPFZ/hX7RtQ==", "cpu": [ "arm64" ], @@ -165,9 +165,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.8.tgz", - "integrity": "sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==", + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.39.0.tgz", + "integrity": "sha512-8RXIWvYIRK9nO+bhVz8DwLBepcptw633gv/QT4015CpJ0Ht8punmoHU/DuEd3iw9Hr8UwUV+t+VNNuZIWYeY7Q==", "cpu": [ "x64" ], @@ -179,9 +179,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.8.tgz", - "integrity": "sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==", + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.39.0.tgz", + "integrity": "sha512-mz5POx5Zu58f2xAG5RaRRhp3IZDK7zXGk5sdEDj4o96HeaXhlUwmLFzNlc4hCQi5sGdR12VDgEUqVSHer0lI9g==", "cpu": [ "arm" ], @@ -193,9 +193,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.8.tgz", - "integrity": "sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==", + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.39.0.tgz", + "integrity": "sha512-+YDwhM6gUAyakl0CD+bMFpdmwIoRDzZYaTWV3SDRBGkMU/VpIBYXXEvkEcTagw/7VVkL2vA29zU4UVy1mP0/Yw==", "cpu": [ "arm" ], @@ -207,9 +207,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.8.tgz", - "integrity": "sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==", + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.39.0.tgz", + "integrity": "sha512-EKf7iF7aK36eEChvlgxGnk7pdJfzfQbNvGV/+l98iiMwU23MwvmV0Ty3pJ0p5WQfm3JRHOytSIqD9LB7Bq7xdQ==", "cpu": [ "arm64" ], @@ -221,9 +221,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.8.tgz", - "integrity": "sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==", + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.39.0.tgz", + "integrity": "sha512-vYanR6MtqC7Z2SNr8gzVnzUul09Wi1kZqJaek3KcIlI/wq5Xtq4ZPIZ0Mr/st/sv/NnaPwy/D4yXg5x0B3aUUA==", "cpu": [ "arm64" ], @@ -235,9 +235,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.8.tgz", - "integrity": "sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==", + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.39.0.tgz", + "integrity": "sha512-NMRUT40+h0FBa5fb+cpxtZoGAggRem16ocVKIv5gDB5uLDgBIwrIsXlGqYbLwW8YyO3WVTk1FkFDjMETYlDqiw==", "cpu": [ "loong64" ], @@ -249,9 +249,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.8.tgz", - "integrity": "sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==", + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.39.0.tgz", + "integrity": "sha512-0pCNnmxgduJ3YRt+D+kJ6Ai/r+TaePu9ZLENl+ZDV/CdVczXl95CbIiwwswu4L+K7uOIGf6tMo2vm8uadRaICQ==", "cpu": [ "ppc64" ], @@ -263,9 +263,23 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.8.tgz", - "integrity": "sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==", + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.39.0.tgz", + "integrity": "sha512-t7j5Zhr7S4bBtksT73bO6c3Qa2AV/HqiGlj9+KB3gNF5upcVkx+HLgxTm8DK4OkzsOYqbdqbLKwvGMhylJCPhQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.39.0.tgz", + "integrity": "sha512-m6cwI86IvQ7M93MQ2RF5SP8tUjD39Y7rjb1qjHgYh28uAPVU8+k/xYWvxRO3/tBN2pZkSMa5RjnPuUIbrwVxeA==", "cpu": [ "riscv64" ], @@ -277,9 +291,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.8.tgz", - "integrity": "sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==", + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.39.0.tgz", + "integrity": "sha512-iRDJd2ebMunnk2rsSBYlsptCyuINvxUfGwOUldjv5M4tpa93K8tFMeYGpNk2+Nxl+OBJnBzy2/JCscGeO507kA==", "cpu": [ "s390x" ], @@ -291,9 +305,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.8.tgz", - "integrity": "sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==", + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.39.0.tgz", + "integrity": "sha512-t9jqYw27R6Lx0XKfEFe5vUeEJ5pF3SGIM6gTfONSMb7DuG6z6wfj2yjcoZxHg129veTqU7+wOhY6GX8wmf90dA==", "cpu": [ "x64" ], @@ -305,9 +319,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.8.tgz", - "integrity": "sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==", + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.39.0.tgz", + "integrity": "sha512-ThFdkrFDP55AIsIZDKSBWEt/JcWlCzydbZHinZ0F/r1h83qbGeenCt/G/wG2O0reuENDD2tawfAj2s8VK7Bugg==", "cpu": [ "x64" ], @@ -319,9 +333,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.8.tgz", - "integrity": "sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==", + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.39.0.tgz", + "integrity": "sha512-jDrLm6yUtbOg2TYB3sBF3acUnAwsIksEYjLeHL+TJv9jg+TmTwdyjnDex27jqEMakNKf3RwwPahDIt7QXCSqRQ==", "cpu": [ "arm64" ], @@ -333,9 +347,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.8.tgz", - "integrity": "sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==", + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.39.0.tgz", + "integrity": "sha512-6w9uMuza+LbLCVoNKL5FSLE7yvYkq9laSd09bwS0tMjkwXrmib/4KmoJcrKhLWHvw19mwU+33ndC69T7weNNjQ==", "cpu": [ "ia32" ], @@ -347,9 +361,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.8.tgz", - "integrity": "sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==", + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.39.0.tgz", + "integrity": "sha512-yAkUOkIKZlK5dl7u6dg897doBgLXmUHhIINM2c+sND3DZwnrdQkkSiDh7N75Ll4mM4dxSkYfXqU9fW3lLkMFug==", "cpu": [ "x64" ], @@ -361,9 +375,9 @@ ] }, "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", "dev": true, "license": "MIT" }, @@ -702,13 +716,13 @@ } }, "node_modules/rollup": { - "version": "4.34.8", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.34.8.tgz", - "integrity": "sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==", + "version": "4.39.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.39.0.tgz", + "integrity": "sha512-thI8kNc02yNvnmJp8dr3fNWJ9tCONDhp6TV35X6HkKGGs9E6q7YWCHbe5vKiTa7TAiNcFEmXKj3X/pG2b3ci0g==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.6" + "@types/estree": "1.0.7" }, "bin": { "rollup": "dist/bin/rollup" @@ -718,25 +732,26 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.34.8", - "@rollup/rollup-android-arm64": "4.34.8", - "@rollup/rollup-darwin-arm64": "4.34.8", - "@rollup/rollup-darwin-x64": "4.34.8", - "@rollup/rollup-freebsd-arm64": "4.34.8", - "@rollup/rollup-freebsd-x64": "4.34.8", - "@rollup/rollup-linux-arm-gnueabihf": "4.34.8", - "@rollup/rollup-linux-arm-musleabihf": "4.34.8", - "@rollup/rollup-linux-arm64-gnu": "4.34.8", - "@rollup/rollup-linux-arm64-musl": "4.34.8", - "@rollup/rollup-linux-loongarch64-gnu": "4.34.8", - "@rollup/rollup-linux-powerpc64le-gnu": "4.34.8", - "@rollup/rollup-linux-riscv64-gnu": "4.34.8", - "@rollup/rollup-linux-s390x-gnu": "4.34.8", - "@rollup/rollup-linux-x64-gnu": "4.34.8", - "@rollup/rollup-linux-x64-musl": "4.34.8", - "@rollup/rollup-win32-arm64-msvc": "4.34.8", - "@rollup/rollup-win32-ia32-msvc": "4.34.8", - "@rollup/rollup-win32-x64-msvc": "4.34.8", + "@rollup/rollup-android-arm-eabi": "4.39.0", + "@rollup/rollup-android-arm64": "4.39.0", + "@rollup/rollup-darwin-arm64": "4.39.0", + "@rollup/rollup-darwin-x64": "4.39.0", + "@rollup/rollup-freebsd-arm64": "4.39.0", + "@rollup/rollup-freebsd-x64": "4.39.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.39.0", + "@rollup/rollup-linux-arm-musleabihf": "4.39.0", + "@rollup/rollup-linux-arm64-gnu": "4.39.0", + "@rollup/rollup-linux-arm64-musl": "4.39.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.39.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.39.0", + "@rollup/rollup-linux-riscv64-gnu": "4.39.0", + "@rollup/rollup-linux-riscv64-musl": "4.39.0", + "@rollup/rollup-linux-s390x-gnu": "4.39.0", + "@rollup/rollup-linux-x64-gnu": "4.39.0", + "@rollup/rollup-linux-x64-musl": "4.39.0", + "@rollup/rollup-win32-arm64-msvc": "4.39.0", + "@rollup/rollup-win32-ia32-msvc": "4.39.0", + "@rollup/rollup-win32-x64-msvc": "4.39.0", "fsevents": "~2.3.2" } }, diff --git a/package.json b/package.json index 74e7d18..159429e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@idotj/mastodon-embed-timeline", - "version": "4.6.0", + "version": "4.7.0", "description": "Displays a Mastodon timeline with posts embed in your website. Very easy to setup, no dependencies, no trackers, cross-browser, WCAG compliant and fully responsive.", "license": "GNU", "author": { @@ -34,7 +34,7 @@ }, "devDependencies": { "clean-css-cli": "^5.6.3", - "rollup": "^4.34.8", + "rollup": "^4.39.0", "@rollup/plugin-terser": "^0.4.4" }, "files": [ diff --git a/src/mastodon-timeline.css b/src/mastodon-timeline.css index c4b82c8..ead9024 100644 --- a/src/mastodon-timeline.css +++ b/src/mastodon-timeline.css @@ -1,4 +1,4 @@ -/* Mastodon embed timeline v4.6.0 */ +/* Mastodon embed timeline v4.7.0 */ /* More info at: */ /* https://gitlab.com/idotj/mastodon-embed-timeline */ diff --git a/src/mastodon-timeline.js b/src/mastodon-timeline.js index a1afae4..c4ce98d 100644 --- a/src/mastodon-timeline.js +++ b/src/mastodon-timeline.js @@ -1,7 +1,7 @@ /** * Mastodon embed timeline * @author idotj - * @version 4.6.0 + * @version 4.7.0 * @url https://gitlab.com/idotj/mastodon-embed-timeline * @license GNU AGPLv3 */ @@ -101,11 +101,6 @@ export class Init { * Find main container in DOM before building the timeline */ #getContainerNode() { - // console.log( - // "Initializing Mastodon timeline with settings: ", - // this.mtSettings - // ); - const assignContainerNode = () => { this.mtContainerNode = document.getElementById( this.mtSettings.mtContainerId @@ -212,12 +207,11 @@ export class Init { const urls = this.#setUrls(instanceApiUrl); const urlsPromises = Object.entries(urls).map(([key, url]) => { - const headers = key === "timeline"; - return this.#fetchData(url, headers) + return this.#fetchData(url, key) .then((data) => ({ [key]: data })) .catch((error) => { reject( - new Error(`Something went wrong fetching data from: ${url}`) + new Error(`Something went wrong getting the timeline data.`) ); this.#showError(error.message); return { [key]: [] }; @@ -269,6 +263,8 @@ export class Init { timelineType, userId, hashtagName, + hideReblog, + hideReplies, maxNbPostFetch, hidePinnedPosts, hideEmojos, @@ -313,6 +309,14 @@ export class Init { ); } + if (hideReblog) { + urls.timeline += "&exclude_reblogs=true"; + } + + if (hideReplies) { + urls.timeline += "&exclude_replies=true"; + } + if (!hideEmojos) { urls.emojos = `${i}custom_emojis`; } @@ -323,10 +327,10 @@ export class Init { /** * Fetch data from server * @param {String} u Url address to fetch - * @param {Boolean} h gets the link header + * @param {String} t Type of data to request * @returns {Array} List of objects */ - async #fetchData(u, h = false) { + async #fetchData(u, t) { const response = await fetch(u); if (!response.ok) { @@ -338,7 +342,7 @@ export class Init { const data = await response.json(); // Get Link headers for pagination - if (h && response.headers.get("Link")) { + if (t === "timeline" && response.headers.get("Link")) { this.linkHeader = this.#parseLinkHeader(response.headers.get("Link")); } @@ -361,10 +365,16 @@ export class Init { #fetchMorePosts() { return new Promise((resolve) => { if (this.linkHeader.next) { - this.#fetchData(this.linkHeader.next, true).then((data) => { - this.fetchedData.timeline = [...this.fetchedData.timeline, ...data]; - resolve(); - }); + this.#fetchData(this.linkHeader.next, "timeline") + .then((data) => { + this.fetchedData.timeline = [...this.fetchedData.timeline, ...data]; + resolve(); + }) + .catch((error) => { + reject(new Error(`Something went wrong fetching more posts.`)); + this.#showError(error.message); + return { [key]: [] }; + }); } else { resolve(); } @@ -392,15 +402,7 @@ export class Init { */ async #buildTimeline(t) { await this.#getTimelineData(); - // console.log("Mastodon timeline data fetched: ", this.fetchedData); - - const { - hideUnlisted, - hideReblog, - hideReplies, - maxNbPostShow, - filterByLanguage, - } = this.mtSettings; + const { hideUnlisted, maxNbPostShow, filterByLanguage } = this.mtSettings; const posts = this.fetchedData.timeline; let nbPostToShow = 0; this.mtBodyNode.replaceChildren(); @@ -409,19 +411,12 @@ export class Init { const isPublicOrUnlisted = post.visibility === "public" || (!hideUnlisted && post.visibility === "unlisted"); - const shouldHideReblog = hideReblog && post.reblog; - const shouldHideReplies = hideReplies && post.in_reply_to_id; const postLanguage = post.language || (post.reblog ? post.reblog.language : null); const matchesLanguage = filterByLanguage === "" || postLanguage === filterByLanguage; - return ( - isPublicOrUnlisted && - !shouldHideReblog && - !shouldHideReplies && - matchesLanguage - ); + return isPublicOrUnlisted && matchesLanguage; }); filteredPosts.forEach((post, index) => { @@ -592,6 +587,12 @@ export class Init { "" + ""; + // Preview link + const previewLinkHTML = + !this.mtSettings.hidePreviewLink && (c.card || c.reblog?.card) + ? this.#createPreviewLink(!isReblog ? c.card : c.reblog.card) + : ""; + // Post text const hasTxtMaxLines = this.mtSettings.txtMaxLines !== "0"; const txtTruncateCss = @@ -604,6 +605,7 @@ export class Init { "" + '
' + this.#formatPostText(post.content) + + previewLinkHTML + "
"; if (textSource) { @@ -630,12 +632,6 @@ export class Init { ? `
${media}
` : ""; - // Preview link - const previewLinkHTML = - !this.mtSettings.hidePreviewLink && (c.card || c.reblog?.card) - ? this.#createPreviewLink(!isReblog ? c.card : c.reblog.card) - : ""; - // Poll const pollHTML = c.poll ? '
" + postTxt + mediaHTML + - previewLinkHTML + pollHTML + + (post.spoiler_text ? "" : previewLinkHTML) + counterBarHTML + "" );