8 lines
17 KiB
JavaScript
8 lines
17 KiB
JavaScript
/**
|
|
* Mastodon embed feed timeline
|
|
* @author idotj
|
|
* @version 4.0.4
|
|
* @url https://gitlab.com/idotj/mastodon-embed-feed-timeline
|
|
* @license GNU AGPLv3
|
|
*/ "use strict";class MastodonTimeline{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",hideUnlisted:!1,hideReblog:!1,hideReplies:!1,hideVideoPreview:!1,hidePreviewLink:!1,hideEmojos:!1,markdownBlockquote:!1,hideCounterBar:!1,txtMaxLines:"0",btnShowMore:"SHOW MORE",btnShowLess:"SHOW LESS",btnShowContent:"SHOW CONTENT",btnSeeMore:"See more posts at Mastodon",btnReload:"Refresh"},this.mtSettings={...this.defaultSettings,...t},this.mtContainerNode="",this.mtBodyNode="",this.fetchedData={},this.mtInit()}onDOMContentLoaded(t){"undefined"!=typeof document&&("complete"===document.readyState||"interactive"===document.readyState)?t():"undefined"!=typeof document&&("complete"!==document.readyState||"interactive"!==document.readyState)&&document.addEventListener("DOMContentLoaded",t)}mtInit(){this.onDOMContentLoaded(()=>{this.mtContainerNode=document.getElementById(this.mtSettings.mtContainerId),this.mtBodyNode=this.mtContainerNode.getElementsByClassName("mt-body")[0],this.#a(),this.#b("newTimeline")})}mtUpdate(){this.onDOMContentLoaded(()=>{this.mtBodyNode.replaceChildren(),this.mtBodyNode.insertAdjacentHTML("afterbegin",'<div class="mt-loading-spinner"></div>'),this.#b("updateTimeline")})}mtColorTheme(t){this.onDOMContentLoaded(()=>{this.mtContainerNode.setAttribute("data-theme",t)})}#a(){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)}#c(){return new Promise((t,e)=>{async function s(t){let e=await fetch(t);if(!e.ok)throw Error("Failed to fetch the following Url: <br>"+t+"<hr>Error status: "+e.status+"<hr>Error message: "+e.statusText);let s=await e.json();return s}let i={};this.mtSettings.instanceUrl?"profile"===this.mtSettings.timelineType?this.mtSettings.userId?i.timeline=`${this.mtSettings.instanceUrl}/api/v1/accounts/${this.mtSettings.userId}/statuses?limit=${this.mtSettings.maxNbPostFetch}`:this.#d("Please check your <strong>userId</strong> value","⚠️"):"hashtag"===this.mtSettings.timelineType?this.mtSettings.hashtagName?i.timeline=`${this.mtSettings.instanceUrl}/api/v1/timelines/tag/${this.mtSettings.hashtagName}?limit=${this.mtSettings.maxNbPostFetch}`:this.#d("Please check your <strong>hashtagName</strong> value","⚠️"):"local"===this.mtSettings.timelineType?i.timeline=`${this.mtSettings.instanceUrl}/api/v1/timelines/public?local=true&limit=${this.mtSettings.maxNbPostFetch}`:this.#d("Please check your <strong>timelineType</strong> value","⚠️"):this.#d("Please check your <strong>instanceUrl</strong> value","⚠️"),this.mtSettings.hideEmojos||(i.emojos=this.mtSettings.instanceUrl+"/api/v1/custom_emojis");let a=Object.entries(i).map(([t,i])=>s(i).then(e=>({[t]:e})).catch(s=>(e(Error("Something went wrong fetching data from: "+i)),this.#d(s.message),{[t]:[]})));Promise.all(a).then(e=>{this.mtSettings.fetchedData=e.reduce((t,e)=>({...t,...e}),{}),t()})})}async #b(e){await this.#c(),this.mtBodyNode.replaceChildren();let s=0;for(let i in this.mtSettings.fetchedData.timeline)("public"==this.mtSettings.fetchedData.timeline[i].visibility||!this.mtSettings.hideUnlisted&&"unlisted"==this.mtSettings.fetchedData.timeline[i].visibility)&&(this.mtSettings.hideReblog&&this.mtSettings.fetchedData.timeline[i].reblog||this.mtSettings.hideReplies&&this.mtSettings.fetchedData.timeline[i].in_reply_to_id||s<this.mtSettings.maxNbPostShow&&(this.#e(this.mtSettings.fetchedData.timeline[i],Number(i)),s++));if(""===this.mtBodyNode.innerHTML){let a="No posts to show <hr/>"+(this.mtSettings.fetchedData.timeline?.length||0)+" posts have been fetched from the server <hr/>This may be due to an incorrect configuration in the parameters or to filters applied (to hide certains type of posts)";this.#d(a,"\uD83D\uDCED")}else"newTimeline"===e?(this.#f(),this.#g(),this.#h()):"updateTimeline"===e?this.#f():this.#d("The function buildTimeline() was expecting a param")}#e(o,n){this.mtBodyNode.insertAdjacentHTML("beforeend",this.#i(o,n))}#i(r,l){let m,d,h,c,p,g,u,v,b;r.reblog?(c=r.reblog.url,m='<a href="'+r.reblog.account.url+'" class="mt-post-avatar" rel="nofollow noopener noreferrer" target="_blank"><div class="mt-post-avatar-boosted"><div class="mt-post-avatar-image-big mt-loading-spinner"><img src="'+r.reblog.account.avatar+'" alt="'+this.#j(r.reblog.account.username)+' avatar" loading="lazy" /></div><div class="mt-post-avatar-image-small"><img src="'+r.account.avatar+'" alt="'+this.#j(r.account.username)+' avatar" loading="lazy" /></div></div></a>',h=r.reblog.account.display_name?r.reblog.account.display_name:r.reblog.account.username,this.mtSettings.hideEmojos||(h=this.#k(h,this.mtSettings.fetchedData.emojos)),d='<div class="mt-post-header-user"><a href="'+r.reblog.account.url+'" rel="nofollow noopener noreferrer" target="_blank">'+h+'<span class="visually-hidden"> account</span></a></div>',p=r.reblog.created_at,b=r.reblog.replies_count,v=r.reblog.reblogs_count,u=r.reblog.favourites_count):(c=r.url,m='<a href="'+r.account.url+'" class="mt-post-avatar" rel="nofollow noopener noreferrer" target="_blank"><div class="mt-post-avatar-standard"><div class="mt-post-avatar-image-big mt-loading-spinner"><img src="'+r.account.avatar+'" alt="'+this.#j(r.account.username)+' avatar" loading="lazy" /></div></div></a>',h=r.account.display_name?r.account.display_name:r.account.username,this.mtSettings.hideEmojos||(h=this.#k(h,this.mtSettings.fetchedData.emojos)),d='<div class="mt-post-header-user"><a href="'+r.account.url+'" rel="nofollow noopener noreferrer" target="_blank">'+h+'<span class="visually-hidden"> account</span></a></div>',p=r.created_at,b=r.replies_count,v=r.reblogs_count,u=r.favourites_count),g=this.#l(p);let S='<div class="mt-post-header-date"><a href="'+c+'" rel="nofollow noopener noreferrer" target="_blank"><time datetime="'+p+'">'+g+"</time></a></div>",$="";"0"!==this.mtSettings.txtMaxLines&&($=" truncate",this.mtBodyNode.parentNode.style.setProperty("--mt-txt-max-lines",this.mtSettings.txtMaxLines));let f="";f=""!==r.spoiler_text?'<div class="mt-post-txt">'+r.spoiler_text+' <button type="button" class="mt-btn-dark mt-btn-spoiler" aria-expanded="false">'+this.mtSettings.btnShowMore+'</button><div class="spoiler-txt-hidden">'+this.#m(r.content)+"</div></div>":r.reblog&&""!==r.reblog.content&&""!==r.reblog.spoiler_text?'<div class="mt-post-txt">'+r.reblog.spoiler_text+' <button type="button" class="mt-btn-dark mt-btn-spoiler" aria-expanded="false">'+this.mtSettings.btnShowMore+'</button><div class="spoiler-txt-hidden">'+this.#m(r.reblog.content)+"</div></div>":r.reblog&&""!==r.reblog.content&&""===r.reblog.spoiler_text?'<div class="mt-post-txt'+$+'"><div class="mt-post-txt-wrapper">'+this.#m(r.reblog.content)+"</div></div>":'<div class="mt-post-txt'+$+'"><div class="mt-post-txt-wrapper">'+this.#m(r.content)+"</div></div>";let _=[];if(r.media_attachments.length>0)for(let w in r.media_attachments)_.push(this.#n(r.media_attachments[w],r.sensitive));if(r.reblog&&r.reblog.media_attachments.length>0)for(let y in r.reblog.media_attachments)_.push(this.#n(r.reblog.media_attachments[y],r.reblog.sensitive));let N="";!this.mtSettings.hidePreviewLink&&r.card&&(N=this.#o(r.card));let x="";if(r.poll){let L="";for(let T in r.poll.options)L+="<li>"+r.poll.options[T].title+"</li>";x='<div class="mt-post-poll '+(r.poll.expired?"mt-post-poll-expired":"")+'"><ul>'+L+"</ul></div>"}let C="";if(!this.mtSettings.hideCounterBar){let M='<div class="mt-post-counter-bar-replies"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 -960 960 960" aria-hidden="true"><path d="M774.913-185.869V-356q0-56.609-35.891-92.5-35.892-35.891-92.5-35.891H258.045L411.435-331l-56 56.566L105.869-524l249.566-249.566 56 56.566-153.39 153.391h388.477q88.957 0 148.566 59.609 59.608 59.609 59.608 148v170.131h-79.783Z"></path></svg>'+b+"</div>",k='<div class="mt-post-counter-bar-reblog"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 -960 960 960" aria-hidden="true"><path d="M276.043-65.304 105.869-236.043l170.174-170.175 52.74 54.175-78.652 78.652h449.304v-160h75.261v235.261H250.131l78.652 78.087-52.74 54.74Zm-90.174-457.348v-235.261h524.565L631.782-836l52.74-54.74L854.696-720 684.522-549.26 631.782-604l78.652-78.652H261.13v160h-75.261Z"></path></svg>'+v+"</div>",E='<div class="mt-post-counter-bar-favorites"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 -960 960 960" aria-hidden="true"><path d="m330.955-216.328 149.066-89 149.066 90.023-40.305-168.391 131.217-114.347-172.956-14.87L480-671.869l-67.043 158.521-172.956 14.305 131.427 113.796-40.473 168.919ZM212.086-50.608l70.652-305.305L45.52-561.305l312.645-26.579L480-876.176l121.835 288.292 312.645 26.579-237.218 205.392 71.217 305.306L480-213.173 212.086-50.607ZM480-433.87Z"></path></svg>'+u+"</div>";C='<div class="mt-post-counter-bar">'+M+k+E+"</div>"}let P='<article class="mt-post" aria-posinset="'+(l+1)+'" aria-setsize="'+this.mtSettings.maxNbPostFetch+'" data-location="'+c+'" tabindex="0"><div class="mt-post-header">'+m+d+S+"</div>"+f+_.join("")+N+x+C+"</article>";return P}#m(B){let H=B;return H=this.#p(H),this.mtSettings.hideEmojos||(H=this.#k(H,this.mtSettings.fetchedData.emojos)),this.mtSettings.markdownBlockquote&&(H=this.#q(H,"<p>>","</p>","<blockquote><p>","</p></blockquote>")),H}#p(j){let A=j.replaceAll('rel="tag"','rel="tag" target="_blank"');return A.replaceAll('class="u-url mention"','class="u-url mention" target="_blank"')}#q(D,U,I,O,F){if(!D.includes(U))return D;{let R=RegExp(U+"(.*?)"+I,"gi");return D.replace(R,O+"$1"+F)}}#j(z){return(z??"").replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}#k(q,Z){if(!q.includes(":"))return q;for(let V of Z){let J=RegExp(`\\:${V.shortcode}\\:`,"g");q=q.replace(J,`<img src="${V.url}" class="mt-custom-emoji" alt="Emoji ${V.shortcode}" />`)}return q}#l(W){let Y=new Date(W),G=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec",][Y.getMonth()]+" "+Y.getDate()+", "+Y.getFullYear();return G}#n(K,Q){let X=Q||!1,tt=K.type,te="";return"image"===tt&&(te='<div class="mt-post-media '+(X?"mt-post-media-spoiler ":"")+this.mtSettings.spinnerClass+'" style="padding-top: calc(100%/'+K.meta.small.aspect+')">'+(X?'<button class="mt-btn-dark mt-btn-spoiler">'+this.mtSettings.btnShowContent+"</button>":"")+'<img src="'+K.preview_url+'" alt="'+(K.description?this.#j(K.description):"")+'" loading="lazy" /></div>'),"audio"===tt&&(te=K.preview_url?'<div class="mt-post-media '+(X?"mt-post-media-spoiler ":"")+this.mtSettings.spinnerClass+'" style="padding-top: calc(100%/'+K.meta.small.aspect+')">'+(X?'<button class="mt-btn-dark mt-btn-spoiler">'+this.mtSettings.btnShowContent+"</button>":"")+'<audio controls src="'+K.url+'"></audio><img src="'+K.preview_url+'" alt="'+(K.description?this.#j(K.description):"")+'" loading="lazy" /></div>':'<div class="mt-post-media '+(X?"mt-post-media-spoiler ":"")+'">'+(X?'<button class="mt-btn-dark mt-btn-spoiler">'+this.mtSettings.btnShowContent+"</button>":"")+'<audio controls src="'+K.url+'"></audio></div>'),("video"===tt||"gifv"===tt)&&(te=this.mtSettings.hideVideoPreview?'<div class="mt-post-media '+(X?"mt-post-media-spoiler ":"")+'" style="padding-top: calc(100%/'+K.meta.small.aspect+')">'+(X?'<button class="mt-btn-dark mt-btn-spoiler">'+this.mtSettings.btnShowContent+"</button>":"")+'<video controls src="'+K.url+'"></video></div>':'<div class="mt-post-media '+(X?"mt-post-media-spoiler ":"")+this.mtSettings.spinnerClass+'" data-video-url="'+K.url+'" style="padding-top: calc(100%/'+K.meta.small.aspect+')">'+(X?'<button class="mt-btn-dark mt-btn-spoiler">'+this.mtSettings.btnShowContent+"</button>":"")+'<img src="'+K.preview_url+'" alt="'+(K.description?this.#j(K.description):"")+'" loading="lazy" /><button class="mt-post-media-play-icon" title="Load video"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 14"><path d="M9.5 7l-9 6.3V.7z"/></svg></button></div>'),te}#r(ts){let ti=ts.target.closest("[data-video-url]"),ta=ti.dataset.videoUrl;ti.replaceChildren(),ti.innerHTML='<video controls src="'+ta+'" autoplay></video>'}#s(to){let tn=to.target.nextSibling;"img"===tn.localName||"audio"===tn.localName||"video"===tn.localName?(to.target.parentNode.classList.remove("mt-post-media-spoiler"),to.target.style.display="none"):(tn.classList.contains("spoiler-txt-hidden")||tn.classList.contains("spoiler-txt-visible"))&&(to.target.textContent==this.mtSettings.btnShowMore?(tn.classList.remove("spoiler-txt-hidden"),tn.classList.add("spoiler-txt-visible"),to.target.setAttribute("aria-expanded","true"),to.target.textContent=this.mtSettings.btnShowLess):(tn.classList.remove("spoiler-txt-visible"),tn.classList.add("spoiler-txt-hidden"),to.target.setAttribute("aria-expanded","false"),to.target.textContent=this.mtSettings.btnShowMore))}#o(tr){let tl='<a href="'+tr.url+'" class="mt-post-preview" target="_blank" rel="noopener noreferrer">'+(tr.image?'<div class="mt-post-preview-image '+this.mtSettings.spinnerClass+'"><img src="'+tr.image+'" alt="'+this.#j(tr.image_description)+'" loading="lazy" /></div>':'<div class="mt-post-preview-noImage">\uD83D\uDCC4</div>')+'</div><div class="mt-post-preview-content">'+(tr.provider_name?'<span class="mt-post-preview-provider">'+this.#t(tr.provider_name)+"</span>":"")+'<span class="mt-post-preview-title">'+tr.title+"</span>"+(tr.author_name?'<span class="mt-post-preview-author">'+this.#t(tr.author_name)+"</span>":"")+"</div></a>";return tl}#t(tm){let td=new DOMParser,th=td.parseFromString(tm,"text/html");return th.body.textContent}#h(){if(this.mtSettings.btnSeeMore||this.mtSettings.btnReload){this.mtBodyNode.parentNode.insertAdjacentHTML("beforeend",'<div class="mt-footer"></div>');let tc=this.mtContainerNode.getElementsByClassName("mt-footer")[0];if(this.mtSettings.btnSeeMore){let tp="";"profile"===this.mtSettings.timelineType?this.mtSettings.profileName?tp=this.mtSettings.profileName:this.#d("Please check your <strong>profileName</strong> value","⚠️"):"hashtag"===this.mtSettings.timelineType?tp="tags/"+this.mtSettings.hashtagName:"local"===this.mtSettings.timelineType&&(tp="public/local");let tg='<a class="mt-btn-violet btn-see-more" href="'+this.mtSettings.instanceUrl+"/"+this.#j(tp)+'" rel="nofollow noopener noreferrer" target="_blank">'+this.mtSettings.btnSeeMore+"</a>";tc.insertAdjacentHTML("beforeend",tg)}if(this.mtSettings.btnReload){let tu='<button class="mt-btn-violet btn-refresh"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none"><path d="M21 3v5m0 0h-5m5 0l-3-2.708C16.408 3.867 14.305 3 12 3a9 9 0 1 0 0 18c4.283 0 7.868-2.992 8.777-7" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>'+this.mtSettings.btnReload+"</button>";tc.insertAdjacentHTML("beforeend",tu);let tv=this.mtContainerNode.getElementsByClassName("btn-refresh")[0];tv.addEventListener("click",()=>{this.mtUpdate()})}}}#g(){this.mtBodyNode.addEventListener("click",t=>{"article"!=t.target.localName&&t.target.offsetParent?.localName!="article"&&("img"!=t.target.localName||t.target.parentNode.getAttribute("data-video-url"))||this.#u(t),"button"==t.target.localName&&t.target.classList.contains("mt-btn-spoiler")&&this.#s(t),("mt-post-media-play-icon"==t.target.className||"svg"==t.target.localName&&"mt-post-media-play-icon"==t.target.parentNode.className||"path"==t.target.localName&&"mt-post-media-play-icon"==t.target.parentNode.parentNode.className||"img"==t.target.localName&&t.target.parentNode.getAttribute("data-video-url"))&&this.#r(t)}),this.mtBodyNode.addEventListener("keydown",t=>{"Enter"===t.key&&"article"==t.target.localName&&this.#u(t)})}#u(tb){let tS=tb.target.closest(".mt-post").dataset.location;"a"!==tb.target.localName&&"span"!==tb.target.localName&&"button"!==tb.target.localName&&"time"!==tb.target.localName&&"mt-post-preview-noImage"!==tb.target.className&&"mt-post-avatar-image-big"!==tb.target.parentNode.className&&"mt-post-avatar-image-small"!==tb.target.parentNode.className&&"mt-post-preview-image"!==tb.target.parentNode.className&&"mt-post-preview"!==tb.target.parentNode.className&&tS&&window.open(tS,"_blank","noopener")}#f(){let t$=t=>{t.target.parentNode.classList.remove(this.mtSettings.spinnerClass),t.target.removeEventListener("load",t$),t.target.removeEventListener("error",t$)};this.mtBodyNode.querySelectorAll(`.${this.mtSettings.spinnerClass} > img`).forEach(t=>{t.addEventListener("load",t$),t.addEventListener("error",t$)})}#d(tf,t_){throw this.mtBodyNode.innerHTML='<div class="mt-error"><span class="mt-error-icon">'+(t_||"❌")+'</span><br/><strong>Oops, something\'s happened:</strong><br/><div class="mt-error-message">'+tf+"</div></div>",this.mtBodyNode.setAttribute("role","none"),Error("Stopping the script due to an error building the timeline.")}}
|