Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Mastodon - Preview Local TL
// ==UserScript==
// @name Mastodon - Preview local TL
// @description Add "Preview local TL" to bottom of signup form.
// @namespace https://github.com/unarist/
// @version 0.10
// @author unarist
// @license MIT license
// @match https://*/about
// @require https://cdnjs.cloudflare.com/ajax/libs/jade/1.11.0/jade.min.js
// @downloadURL https://gist.github.com/unarist/6d06ad73945b5a369f6d593b1a2cfba8/raw/mastodon-preview-local-tl.user.js
// @grant none
// ==/UserScript==
/* globals jade */
// 使い方:
// 1. GreasemonkeyかTampermonkeyを入れます
// 2. このGistの右上にあるRawボタンをクリックしてインストール
// 3. 各鯖のトップページ(/about)のユーザー登録フォームにしれっと "Preview local TL" ってのが増えてます
// 4. リロードや続きを読むはありません。が、ヘッダ部分をクリックして閉じて、また開きなおせば読み直します
// 自前のscriptタグ挿入も用意してあるので、CSPで制限されていないサイトならbookmarkletとしても使えるはず。
// まあJade使わなければいいって話ではある。
/* history
0.10: remove jQuery dependency
0.9: show timestamp using toLocaleString()
0.8: fix "TypeError: ... is not valid URL" error
0.7: improve instance compatibility with more use of Mastoson's CSS classes (i.e. support kktCSS v8)
0.6: improve Mastodon detection, fix insertion point (i.e. support mastodon.cloud)
0.5: fix for transparent backgrounds (e.g. kktCSS)
0.4: add support for closed instances (find .screenshot-with-signup instead of #new_user)
0.3: use @require for CSP-enabled sites (but keeps <script> injection as fallback)
0.2: implement spoilers, fix timeline width
0.1: release
*/
(() => {
'use strict';
if (!document.querySelector('.screenshot-with-signup')) return;
let activities_template_src = `
each toot in toots
.entry.h-entry
.status.light
.status__header
.status__meta
- time = new Date(toot.created_at)
a.status__relative-time.u-url.u-uid(href=toot.url rel='noopener') #{time < today ? time.toLocaleString() : time.toLocaleTimeString()}
a.status__display-name.p-author.h-card(href=toot.account.url rel='noopener')
.status__avatar
div: img.u-photo(height='48' width='48' src=toot.account.avatar_static)
span.display-name
strong.p-name.emojify #{toot.account.display_name || toot.account.username}
span @#{toot.account.acct}
.status__content.p-name.emojify
if toot.spoiler_text
p(style='margin-bottom: 0')
span.p-summary #{toot.spoiler_text}
a.status__content__spoiler-link(href='#') もっと見る
.e-content(style='display: block; direction: ltr') !{toot.content}
.status__attachments
if toot.sensitive
.media-spoiler
span 不適切なコンテンツの可能性があります
span クリックして表示
each media in toot.media_attachments
.status__attachments__inner
.media-item: a.u-photo(
href=media.url rel='noopener' target='_blank'
style='background-image: url(#{media.preview_url})'
)
`;
if (window.jade) {
install();
} else {
document.head.appendChild(Object.assign(document.createElement('script'), {
src: 'https://cdnjs.cloudflare.com/ajax/libs/jade/1.11.0/jade.min.js'
})).addEventListener('load', install);
}
function install() {
let link = Object.assign(document.createElement('a'), {
href: '#',
onclick: e => { e.preventDefault(); showTL(); },
textContent: 'Preview local TL'
});
let target = document.querySelector('.screenshot-with-signup .info');
target.appendChild(document.createElement('br'));
target.appendChild(link);
let style = Object.assign(document.createElement('style'), {
textContent: '.preview-local-tl-panel ~ * { display: none !important; }'
});
document.head.appendChild(style);
}
function showTL() {
fetch(location.origin + '/api/v1/timelines/public?local=true')
.then(resp => {
if (!resp.ok) throw new Error(resp.statusText);
return resp.json();
})
.then(toots => {
let first_paragraph = document.querySelector('.wrapper > :nth-child(2)');
let parent = first_paragraph.parentElement;
let panel = Object.assign(document.createElement('div'), {className: 'preview-local-tl-panel'});
let header = Object.assign(document.createElement('p'), {
className: 'column-header',
textContent: 'Local TL (click here to close)',
onclick: () => panel.parentElement.removeChild(panel)
});
Object.assign(header.style, {
textAlign: 'center',
margin: 0,
});
panel.appendChild(header);
let today = new Date();
today.setHours(0, 0, 0, 0);
let activities = Object.assign(document.createElement('div'), {className: 'activity-stream'});
activities.innerHTML = jade.render(activities_template_src, { today, toots });
for (let activity of activities.children) {
let content_spoiler = activity.querySelector('.status__content__spoiler-link');
if (content_spoiler) {
let content = activity.querySelector('.e-content');
content.style.display = 'none';
content_spoiler.addEventListener('click', e => { e.preventDefault(); content.style.display = content.style.display ? '' : 'none'; });
}
let media_spoiler = activity.querySelector('.media-spoiler');
if (media_spoiler) {
media_spoiler.addEventListener('click', e => { e.preventDefault(); media_spoiler.style.display = 'none'; });
}
}
panel.appendChild(activities);
first_paragraph.parentElement.insertBefore(panel, first_paragraph);
})
.catch(reason => alert(reason));
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment