fedilove-ui/static/fedilove-no-react.js

221 lines
8.9 KiB
JavaScript
Raw Normal View History

// I'm not a React developer. Be advised!
// If you are, and want to rewrite this the "right way", go ahead and do it :)
// This is plain Javascript and only requires basic calls to implement customizations
// Do simple XHR requests to the API on Mastodon
// make sure you control errors correctly, as a Mastodon Server might not setup CORS correctly
function mastodon_get(path, payload, callbk) { return mastodon_request('GET', path, payload, callbk); }
function mastodon_post(path, payload, callbk) { return mastodon_request('POST', path, payload, callbk); }
function mastodon_request(method, path, payload, callbk) {
payload = payload || null;
var url = 'https://'+fediloveApi.getCurrentInstance()+path;
var oReq = new XMLHttpRequest();
oReq.addEventListener("load", function() { callbk(this.responseText); });
oReq.open(method, url);
oReq.setRequestHeader('Authorization', 'Bearer '+fediloveApi.getAccessToken());
oReq.send(payload);
}
function api_status_fav(dom, status_id) {
var dislike = false;
var path = `/api/v1/statuses/${status_id}/favourite`;
if (dom.getAttribute('data-liked') === "1") {
path = `/api/v1/statuses/${status_id}/unfavourite`;
dislike = true;
}
mastodon_post(path, {}, function(data) {
// to-do: check "data" if the POST succeded (for now we expect it did xD)
if (!dislike) {
$(dom).addClass('liked-msg');
$(dom).attr('data-liked', 1);
dom.style.animation = "spin2 .5s linear 1";
} else {
$(dom).removeClass('liked-msg');
$(dom).attr('aria-label', '0 '+$(dom).attr('aria-label'));
$(dom).removeAttr('data-liked');
dom.style.animation = undefined;
}
});
}
// We use the already polished compose system to trick it to send messages using our custom UI
// instead of the reply compose box show in every message when you hit "reply"
function api_send_message(dom) {
// the status_id is the last part of our current URL
const status_id = fediloveApi.getChatStatusId();
// search for the reply on status_id, dictated by URL
$('button[id*=reply-]').each(function(i) {
if ($(this).attr('id').includes('//'+status_id))
{
// click the reply button on the current status, dictated by URL
if ($('#the-compose-box-input-'+status_id).length == 0) {
$(this).click();
}
// wait for the button event to make the compose layer "visible"
var _this = setInterval(function()
{
if ($('#the-compose-box-input-'+status_id).length > 0) {
// search for the user ID in the title attribute
$('a[id*=status-author-name-]').each(function(i2) {
if ($(this).attr('id').includes('//'+status_id))
{
// title contains the user ID on this server
var text = $(this).attr('title')+' '+$('div#chat-compose-global textarea').val();
// set the text on thie invisible compose box of the status_id
$('textarea#the-compose-box-input-'+status_id).val(text);
// hit send :)
$('div#list-item-'+status_id+' div.status-article-compose-box > div.compose-box-button-wrapper button.compose-box-button').click();
// empty our message box
$('div#chat-compose-global textarea').val('');
fediloveUI.scrollChatToLastItem();
}
});
clearInterval(_this);
}
}, 100);
}
});
}
var fediloveUI = {
scrollChatToLastItem: function() {
const startLen = $('div.the-list > div').length;
var count = 0;
var _this = setInterval(function() {
count++;
var newLen = $('div.the-list > div').length;
if (count >= 100 || newLen != startLen) {
document.querySelector('div.the-list > div:last-child').scrollIntoView();
clearInterval(_this);
}
}, 150);
}
};
// objects to access from React code
var fediloveApi = {
getAccessToken: function() {
var instance = fediloveApi.getCurrentInstance();
return JSON.parse(localStorage.store_loggedInInstances)[instance].access_token;
},
getCurrentInstance: function() {
return JSON.parse(localStorage.store_currentInstance);
},
getChatStatusId: function() {
var parts = window.location.pathname.split('/');
return parts[parts.length-1];
}
};
var fediloveReact = {};
var fediloveFunctions = {};
var fediloveData = {
currentChat: null
};
var fediloveEvents = {
onEmojiPicked: function(emoji) {
var $txt = $("#chat-compose-global textarea");
var caretPos = $txt[0].selectionStart;
var textAreaTxt = $txt.val();
$txt.val(textAreaTxt.substring(0, caretPos) + emoji + textAreaTxt.substring(caretPos));
},
onNewNotification: function (dataItems) {
if (window.location.pathname.startsWith('/statuses/')) {
if (fediloveFunctions.updateStatusAndThread !== undefined) {
fediloveFunctions.updateStatusAndThread( fediloveApi.getCurrentInstance(), fediloveApi.getAccessToken(),
window.location.pathname, fediloveApi.getChatStatusId() );
fediloveUI.scrollChatToLastItem();
}
}
}
};
// this is our URL-based customizations made by JavaScript
var intervalChatCssChange = null;
function fedilove_customization() {
document.querySelector('.main-content').classList = "main-content";
document.querySelector('#chat-compose-global').style = 'visibility: collapse';
if (window.location.pathname.startsWith('/statuses/'))
{
$('div.main-content').addClass('chat');
document.querySelector('#chat-compose-global').style = '';
// add some animations
var style = document.createElement('style');
style.innerHTML = '@keyframes spin2 { 100% { transform:rotate(-360deg); } }';
document.body.appendChild(style);
// this function changes the css class on articles (messages)
// that match the given account_id
var makeMessageUIModifications = function(account_id) {
if (intervalChatCssChange !== null) return;
var theint = 150;
setInterval(function()
{
intervalChatCssChange = this;
// paint MY messages as mine
$('div.main-content.chat article.status-article').each(function(i) {
if ($(this).find('a.status-author-name').attr('href').endsWith(`/accounts/${account_id}`)) {
$(this).addClass('mymsg');
theint = 250;
}
});
// paint LIKES
$('a.status-favs-reblogs.status-favs').each(function(i) {
// easy, aria-label contains the times this status was fav
// so, we use this as the input source to search for "0",
// if no "0" found in text, we mark element as liked so we can apply styles and "undo like" function
if ($(this).attr('aria-label').search(/0/) == -1) {
$(this).addClass('liked-msg');
$(this).attr('data-liked', 1);
}
});
}, theint);
};
// get the userAccountId to check against the href /account/NUM on the messages
// so we can apply different style to my messages
if (localStorage.store_userAccountId === undefined) {
mastodon_get('/api/v1/accounts/verify_credentials', {}, function(data) {
var json = JSON.parse(data);
if (json !== undefined) {
localStorage.store_userAccountId = json.id;
makeMessageUIModifications(json.id);
}
});
} else {
makeMessageUIModifications(localStorage.store_userAccountId);
}
}
else if (window.location.pathname == '/direct') {
$('div.main-content').addClass('direct');
}
else if (window.location.pathname.startsWith('/notifications/mentions')) {
$('nav.notification-filters li > a.focus-fix').attr('onclick', 'return false;');
}
}
// we inject this script.js into the React framework at timelines.js
// Watch for URL changes every 1/2 seconds (this is efficient, don't worry about it!)
// and dispatch a call to "fedilove_customization" to load page customizations depending on URL context
var theurl = null;
setInterval(function() {
var newurl = window.location.pathname;
if (newurl != theurl) {
fedilove_customization();
theurl = newurl;
}
}, 250);