Add MBViewer

This commit is contained in:
octospacc 2024-01-13 20:21:17 +01:00
parent 646187cfcd
commit da9531e616
15 changed files with 10597 additions and 5 deletions

View File

@ -1,9 +1,9 @@
# The OctoSpacc Hub
* Website: <https://hub.octt.eu.org/>
* Website: <https://hub.octt.eu.org/>.
Main hosting for my web stuff.
Secondary content is hosted in other repos.
This is the main hosting for my web stuff.
Secondary or more specific content is hosted in other repos.
* Main repository: <https://gitlab.com/octospacc/octospacc.gitlab.io>
* Backup repositories: <https://github.com/octospacc/OctoSpaccHub/>
* Main repository: <https://gitlab.com/octospacc/octospacc.gitlab.io/>.
* Backup repositories: <https://github.com/octospacc/OctoSpaccHub/>, <https://gitea.it/octospacc/OctoSpaccHub/>.

1
public/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.bak

View File

@ -0,0 +1,8 @@
.MBPost * {
max-width: 100%;
height: auto;
}
.MBPost figure {
margin: 1em;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 226 KiB

195
public/MBViewer/index.html Normal file
View File

@ -0,0 +1,195 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>MBViewer</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
<meta name="format-detection" content="telephone=no"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="MobileOptimized" content="176"/>
<meta name="HandheldFriendly" content="True"/>
<meta property="og:title" content="MBViewer"/>
<!--
<meta property="og:image" content=""/>
<meta property="og:description" content=""/>
-->
<meta property="twitter:title" content="MBViewer"/>
<!--
<meta property="twitter:image" content=""/>
<meta name="twitter:card" content="summary"/>
<meta name="twitter:description" content=""/>
-->
<script>
window.matchMedia &&
window.matchMedia('(prefers-color-scheme: dark)').matches &&
document.documentElement &&
document.documentElement.classList &&
document.documentElement.classList.add('theme_dark');
</script>
<link rel="icon" type="image/svg+xml" href="img/website_icon.svg"/>
<link rel="apple-touch-icon" sizes="180x180" href="img/apple-touch-icon.png"/>
<link rel="icon" type="image/png" sizes="32x32" href="img/favicon-32x32.png"/>
<link rel="icon" type="image/png" sizes="16x16" href="img/favicon-16x16.png"/>
<link rel="alternate icon" href="img/favicon.ico" type="image/x-icon"/>
<link href="css/font-roboto.css" rel="stylesheet" type="text/css"/>
<link href="css/widget-frame.css" rel="stylesheet" media="screen"/>
<link href="css/telegram-web.css" rel="stylesheet" media="screen"/>
<link rel="stylesheet" href="css/MBViewer.css"/>
</head>
<body class="widget_frame_base tgme_webpreview emoji_image thin_box_shadow tme_mode no_transitions">
<div class="tgme_background_wrap">
<canvas id="tgme_background" class="tgme_background" width="50" height="50" data-colors="dbddbb,6ba587,d5d88d,88b884"></canvas>
<div class="tgme_background_pattern"></div>
</div>
<header class="tgme_header search_collapsed">
<div class="tgme_container">
<div class="tgme_header_search">
<form class="tgme_header_search_form">
<svg class="tgme_header_search_form_icon" width="20" height="20" viewBox="0 0 20 20">
<g fill="none" stroke="#7D7F81" stroke-width="1.4">
<circle cx="9" cy="9" r="6"/>
<path d="M13.5,13.5 L17,17" stroke-linecap="round"/>
</g>
</svg>
<input class="tgme_header_search_form_input js-header_search" placeholder="Search" name="s" autocomplete="off" value=""/>
<a class="tgme_header_search_form_clear">
<svg class="tgme_action_button_icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" width="20" height="20">
<g class="icon_body" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke="#000000" stroke-width="1.5">
<path d="M6 14l8-8m0 8L6 6" stroke-dasharray="0,11.314" stroke-dashoffset="5.657"/>
<path d="M26 14l8-8m0 8l-8-8" stroke-dasharray="0.371,10.943" stroke-dashoffset="5.842"/>
<path d="M46 14l8-8m0 8l-8-8" stroke-dasharray="1.982,9.332" stroke-dashoffset="6.647756"/>
<path d="M66 14l8-8m0 8l-8-8" stroke-dasharray="5.173,6.14" stroke-dashoffset="8.243"/>
<path d="M86 14l8-8m0 8l-8-8" stroke-dasharray="7.866,3.448" stroke-dashoffset="9.59"/>
<path d="M106 14l8-8m0 8l-8-8" stroke-dasharray="9.471,1.843" stroke-dashoffset="10.392"/>
<path d="M126 14l8-8m0 8l-8-8" stroke-dasharray="10.417,0.896" stroke-dashoffset="10.866"/>
<path d="M146 14l8-8m0 8l-8-8" stroke-dasharray="10.961,0.353" stroke-dashoffset="11.137"/>
<path d="M166 14l8-8m0 8l-8-8" stroke-dasharray="11.234,0.08" stroke-dashoffset="11.274"/>
<path d="M186 14l8-8m0 8l-8-8"/>
</g>
</svg>
</a>
</form>
</div>
<div class="tgme_header_right_column">
<section class="tgme_right_column">
<div class="tgme_channel_info">
<div class="tgme_channel_info_header">
<i class="tgme_page_photo_image"></i>
<div class="tgme_channel_info_header_title_wrap">
<div class="tgme_channel_info_header_title"></div>
<div class="tgme_channel_info_header_labels"></div>
</div>
<div class="tgme_channel_info_header_username"></div>
</div>
<div class="tgme_channel_info_counters" style="min-width: 100%;">
<!--
<div class="tgme_channel_info_counter">
<span class="counter_value">
0
</span>
<span class="counter_type">
subscribers
</span>
</div>
<div class="tgme_channel_info_counter">
<span class="counter_value">
0
</span>
<span class="counter_type">
photos
</span>
</div>
<div class="tgme_channel_info_counter">
<span class="counter_value">
0
</span>
<span class="counter_type">
videos
</span>
</div>
<div class="tgme_channel_info_counter">
<span class="counter_value">
0
</span>
<span class="counter_type">
files
</span>
</div>
<div class="tgme_channel_info_counter">
<span class="counter_value">
0
</span>
<span class="counter_type">
links
</span>
</div>
-->
</div>
<div class="tgme_channel_info_description"></div>
<!--
<a class="tgme_channel_download_telegram" href="dl?tme=f036ac1a4091d93f77_16903051027483582417">
<svg class="tgme_channel_download_telegram_icon" width="21px" height="18px" viewBox="0 0 21 18"><g fill="none"><path fill="#ffffff" d="M0.554,7.092 L19.117,0.078 C19.737,-0.156 20.429,0.156 20.663,0.776 C20.745,0.994 20.763,1.23 20.713,1.457 L17.513,16.059 C17.351,16.799 16.62,17.268 15.88,17.105 C15.696,17.065 15.523,16.987 15.37,16.877 L8.997,12.271 C8.614,11.994 8.527,11.458 8.805,11.074 C8.835,11.033 8.869,10.994 8.905,10.958 L15.458,4.661 C15.594,4.53 15.598,4.313 15.467,4.176 C15.354,4.059 15.174,4.037 15.036,4.125 L6.104,9.795 C5.575,10.131 4.922,10.207 4.329,10.002 L0.577,8.704 C0.13,8.55 -0.107,8.061 0.047,7.614 C0.131,7.374 0.316,7.182 0.554,7.092 Z"></path></g></svg>Download Telegram
</a>
-->
<!--
<div class="tgme_footer">
<div class="tgme_footer_column">
<h5><a href="faq">About</a></h5>
</div>
<div class="tgme_footer_column">
<h5><a href="blog">Blog</a></h5>
</div>
<div class="tgme_footer_column">
<h5><a href="apps">Apps</a></h5>
</div>
<div class="tgme_footer_column">
<h5><a href="//core.telegram.org/">Platform</a></h5>
</div>
</div>
-->
</div>
</section>
</div>
<div class="tgme_header_info">
<!--
<a class="tgme_channel_join_telegram" href="dl?tme=f036ac1a4091d93f77_16903051027483582417">
<svg class="tgme_channel_join_telegram_icon" width="19px" height="16px" viewBox="0 0 19 16">
<g fill="none">
<path fill="#ffffff" d="M0.465,6.638 L17.511,0.073 C18.078,-0.145 18.714,0.137 18.932,0.704 C19.009,0.903 19.026,1.121 18.981,1.33 L16.042,15.001 C15.896,15.679 15.228,16.111 14.549,15.965 C14.375,15.928 14.211,15.854 14.068,15.748 L8.223,11.443 C7.874,11.185 7.799,10.694 8.057,10.345 C8.082,10.311 8.109,10.279 8.139,10.249 L14.191,4.322 C14.315,4.201 14.317,4.002 14.195,3.878 C14.091,3.771 13.926,3.753 13.8,3.834 L5.602,9.138 C5.112,9.456 4.502,9.528 3.952,9.333 L0.486,8.112 C0.077,7.967 -0.138,7.519 0.007,7.11 C0.083,6.893 0.25,6.721 0.465,6.638 Z"></path>
</g>
</svg>
Join
</a>
-->
<a class="tgme_header_link">
<i class="tgme_page_photo_image"></i>
<div class="tgme_header_title_wrap">
<div class="tgme_header_title"></div>
<div class="tgme_header_labels"></div>
</div>
<div class="tgme_header_counter">
Beta
</div>
</a>
</div>
</div>
</header>
<main class="tgme_main">
<div class="tgme_container">
<section class="tgme_channel_history js-message_history"></section>
</div>
</main>
<div id="BottomAnchor"></div>
<script src="js/jquery.min.js"></script>
<script src="js/jquery-ui.min.js"></script>
<script src="js/tgwallpaper.min.js"></script>
<script src="js/tgsticker.js"></script>
<script src="js/widget-frame.js"></script>
<script src="js/telegram-web.js"></script>
<script src="js/MBViewer.js"></script>
<script>
TWeb.init();
MbViewerInit();
</script>
</body>
</html>

View File

@ -0,0 +1,154 @@
// TODO:
// * handle opening the feed at a specific post id in time
// * custom colors
// * author profiles, bios, and showing only their messages instead of the full site
// * show site/profile info on click of navbar for mobile
// * in-app search of site content
// * homepage with history and sponsored sources
// * don't show redundant day markers
// * navigate markdown Wordpress export pages from Git
// * app info in page without JS
let MbState = {};
function GetDomainFromUrl (url) {
return url.split('//')[1].split('/')[0];
}
function MakeSiteRestUrl (path='') {
const siteUrl = MbState.siteUrl;
if (GetDomainFromUrl(siteUrl).toLowerCase() === 'octospacc.altervista.org') {
return `${siteUrl}/wp-content/uploads/${siteUrl.split('.').slice(0, 1)[0].split('//')[1]}/scripts/stuff.php?&Thing=SiteWpJsonCors&AccessToken=9ab6e20c&$Query=${path}`;
} else {
// TODO: universal cors bypass
return `${siteUrl}/wp-json/${path}`;
}
}
async function MbViewerInit () {
if (!location.hash) {
location.hash = '/';
}
MbState = {
siteData: {
name: "MBViewer",
description: "",
},
};
$('form.tgme_header_search_form')[0].action = '';
$('form.tgme_header_search_form')[0].onsubmit = function(event){
location.hash = `/siteUrl=${event.target.querySelector('input').value}`;
event.preventDefault();
};
$('a.tgme_header_link')[0].href = '';
$('.tgme_channel_info_header_username').html('');
$('.tgme_page_photo_image').html('');
$('.tgme_page_photo_image').removeClass('bgcolor0');
$('.tgme_page_photo_image').attr('data-content', '');
$('section.tgme_channel_history.js-message_history').html('');
for (const arg of location.hash.split('/').slice(1).join('/').split('|')) {
const argTokens = arg.split('=');
MbState[argTokens[0]] = argTokens.slice(1).join('=');
}
if (MbState.siteUrl) {
const siteRequest = await fetch(MakeSiteRestUrl());
MbState.siteData = await siteRequest.json();
$('form.tgme_header_search_form')[0].action = `${MbState.siteUrl}/?s`;
$('form.tgme_header_search_form')[0].onsubmit = null;
$('a.tgme_header_link')[0].href = MbState.siteUrl;
$('.tgme_channel_info_header_username').html(`<a href="${MbState.siteUrl}">${GetDomainFromUrl(MbState.siteUrl).toLowerCase()}</a>`);
$('.tgme_page_photo_image').html(`<img src="${MbState.siteUrl}${MbState.siteData.site_icon_url}"/>`);
} else {
$('.tgme_page_photo_image').addClass('bgcolor0');
$('.tgme_page_photo_image').attr('data-content', 'MBV');
$('section.tgme_channel_history.js-message_history').append(MakeMbHtml({ content: `
<p>
MBViewer WIP Version, 2024-01-13.
</p>
<p>
Uses code borrowed from <a href="https://t.me">t.me</a>, specially modified to handle custom MB-style data visualization.
This webapp is not affiliated with Telegram, and all rights upon the original materials belong to the original owners.
</p>
</p>` }));
}
$('.tgme_header_title, .tgme_channel_info_header_title').html(MbState.siteData.name);
$('.tgme_channel_info_description').html(MbState.siteData.description);
//const postsRequest = await fetch(MakeSiteRestUrl('wp/v2/posts/?&offset=0&per_page=1'));
//const postsData = await postsRequest.json();
// // TODO: since this request already gives us the content of the latest post, maybe we can cache it somewhere to avoid wasting too much traffic?
//$('section.tgme_channel_history.js-message_history').append(MakeMoreWrapperHtml(postsData[0].id, 'before'));
$('section.tgme_channel_history.js-message_history').append(MakeMoreWrapperHtml(0, 'before'));
TWeb.loadMore($('.js-messages_more_wrap > a'), true);
// TODO: scroll to the very bottom of the document somehow after showing a first message, to have a less jarring visual effect?
}
//function MakeMoreWrapperHtml (postId, wrapType) {
// return `<div class="tgme_widget_message_centered js-messages_more_wrap">
// <a href="${MakeSiteRestUrl(`wp/v2/posts/${postId}`)}" data-${wrapType}="" class="tme_messages_more js-messages_more"></a>
// </div>`
//}
function MakeMoreWrapperHtml (postOffset, wrapType) {
MbState.lastPostOffset = (postOffset + 1);
return `<div class="tgme_widget_message_centered js-messages_more_wrap">
<a href="${MakeSiteRestUrl(`wp/v2/posts/?offset=${postOffset}&per_page=1`)}" data-${wrapType}="" class="tme_messages_more js-messages_more"></a>
</div>`
}
function MakeMbHtml (postData) {
postData = (typeof(postData) === 'string' ? JSON.parse(postData) : postData);
postData = (postData[0] || postData);
return `
${MbState.siteUrl ? MakeMoreWrapperHtml(MbState.lastPostOffset, 'before') : ''}
<div class="tgme_widget_message_wrap js-widget_message_wrap date_visible">
<div class="tgme_widget_message text_not_supported_wrap js-widget_message" data-post="SpaccInc/1068">
<div class="tgme_widget_message_user">
<a href="${MbState.siteUrl}">
<i class="tgme_widget_message_user_photo ${MbState.siteUrl ? '' : 'bgcolor0'}" style="background-color: unset;" data-content="${MbState.siteUrl ? '' : 'MBV'}">
${MbState.siteUrl ? `<img src="${MbState.siteUrl}${MbState.siteData.site_icon_url}"/>` : ''}
</i>
</a>
</div>
<div class="tgme_widget_message_bubble">
<i class="tgme_widget_message_bubble_tail">
<svg class="bubble_icon" width="9px" height="20px" viewBox="0 0 9 20">
<g fill="none">
<path class="background" fill="#ffffff" d="M8,1 L9,1 L9,20 L8,20 L8,18 C7.807,15.161 7.124,12.233 5.950,9.218 C5.046,6.893 3.504,4.733 1.325,2.738 L1.325,2.738 C0.917,2.365 0.89,1.732 1.263,1.325 C1.452,1.118 1.72,1 2,1 L8,1 Z"></path>
<path class="border_1x" fill="#d7e3ec" d="M9,1 L2,1 C1.72,1 1.452,1.118 1.263,1.325 C0.89,1.732 0.917,2.365 1.325,2.738 C3.504,4.733 5.046,6.893 5.95,9.218 C7.124,12.233 7.807,15.161 8,18 L8,20 L9,20 L9,1 Z M2,0 L9,0 L9,20 L7,20 L7,20 L7.002,18.068 C6.816,15.333 6.156,12.504 5.018,9.58 C4.172,7.406 2.72,5.371 0.649,3.475 C-0.165,2.729 -0.221,1.464 0.525,0.649 C0.904,0.236 1.439,0 2,0 Z"></path>
<path class="border_2x" d="M9,1 L2,1 C1.72,1 1.452,1.118 1.263,1.325 C0.89,1.732 0.917,2.365 1.325,2.738 C3.504,4.733 5.046,6.893 5.95,9.218 C7.124,12.233 7.807,15.161 8,18 L8,20 L9,20 L9,1 Z M2,0.5 L9,0.5 L9,20 L7.5,20 L7.5,20 L7.501,18.034 C7.312,15.247 6.64,12.369 5.484,9.399 C4.609,7.15 3.112,5.052 0.987,3.106 C0.376,2.547 0.334,1.598 0.894,0.987 C1.178,0.677 1.579,0.5 2,0.5 Z"></path>
<path class="border_3x" d="M9,1 L2,1 C1.72,1 1.452,1.118 1.263,1.325 C0.89,1.732 0.917,2.365 1.325,2.738 C3.504,4.733 5.046,6.893 5.95,9.218 C7.124,12.233 7.807,15.161 8,18 L8,20 L9,20 L9,1 Z M2,0.667 L9,0.667 L9,20 L7.667,20 L7.667,20 L7.668,18.023 C7.477,15.218 6.802,12.324 5.64,9.338 C4.755,7.064 3.243,4.946 1.1,2.983 C0.557,2.486 0.52,1.643 1.017,1.1 C1.269,0.824 1.626,0.667 2,0.667 Z"></path>
</g>
</svg>
</i>
<div class="tgme_widget_message_author accent_color">
<a class="tgme_widget_message_owner_name" href="${MbState.siteUrl}">
<span dir="auto">
${MbState.siteData.name}
</span>
</a>
</div>
<div class="tgme_widget_message_text js-message_text before_footer" dir="auto">
<div class="MBPost">
${postData.content?.rendered || postData.content}
</div>
</div>
<div class="tgme_widget_message_footer compact js-message_footer">
<div class="tgme_widget_message_info short js-message_info">
<span class="tgme_widget_message_meta">
<a class="tgme_widget_message_date" href="${postData.link}">
<time datetime="${postData.date}" class="time"></time>
<!-- TODO: show edited status -->
</a>
</span>
</div>
</div>
</div>
</div>
</div>
`;
}
window.addEventListener('hashchange', MbViewerInit);

9
public/MBViewer/js/jquery-ui.min.js vendored Normal file

File diff suppressed because one or more lines are too long

4
public/MBViewer/js/jquery.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,342 @@
(function($) {
$.fn.redraw = function() {
return this.map(function(){ this.offsetTop; return this; });
};
$.fn.scrollIntoView = function(options) {
options = options || {}
return this.first().each(function() {
var position = options.position || 'auto',
padding = options.padding || 0,
duration = options.duration || 0;
var $item = $(this),
$cont = $item.scrollParent(),
scrollTop = $cont.scrollTop(),
positionTop = 0,
paddingTop = 0,
itemHeight = $item.outerHeight(),
isBody = false;
if ($cont.get(0) === document) {
isBody = true;
$cont = $(window);
positionTop = $item.offset().top;
paddingTop = $('header').height() + 1;
} else {
positionTop = $item.offset().top - $cont.offset().top + scrollTop;
}
if (options.slidedEl) {
if (options.slidedEl === 'this') {
options.slidedEl = this;
}
$(options.slidedEl, this).each(function() {
itemHeight += (this.scrollHeight - this.clientHeight);
});
}
var itemTop = positionTop,
itemBottom = itemTop + itemHeight,
contHeight = $cont.height(),
contTop = scrollTop + padding + paddingTop,
contBottom = scrollTop + contHeight - padding,
scrollTo = null;
if (position == 'auto') {
if (itemTop < contTop) {
scrollTo = itemTop - padding - paddingTop;
} else if (itemBottom > contBottom) {
if (itemHeight > contHeight - padding - padding) {
scrollTo = itemTop - padding - paddingTop;
} else {
scrollTo = itemBottom - contHeight + padding;
}
}
} else if (position == 'top' || position == 'center') {
if (contHeight > itemHeight) {
padding = (contHeight - paddingTop - itemHeight) / 2;
}
scrollTo = itemTop - padding - paddingTop;
} else if (position == 'bottom') {
if (itemHeight > contHeight - padding - padding) {
scrollTo = itemTop - padding - paddingTop;
} else {
scrollTo = itemBottom - contHeight + padding;
}
}
if (scrollTo) {
if (duration) {
if (isBody) {
$cont = $('html');
}
$cont.stop().animate({scrollTop: scrollTo}, duration);
} else {
$cont.scrollTop(scrollTo);
}
}
});
};
})(jQuery);
function doesSupportThinBoxShadow() {
if (!window.getComputedStyle) return;
var div = document.createElement('div');
div.style.boxShadow = '0 0 0 0.5px black';
div.style.display = 'none';
document.body.appendChild(div);
var box_shadow = window.getComputedStyle(div).boxShadow;
document.body.removeChild(div);
return box_shadow.indexOf('0.5') >= 0;
}
function formatDate(datetime) {
var date = new Date(datetime);
var cur_date = new Date();
var j = date.getDate();
var M = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'][date.getMonth()];
var Y = date.getFullYear();
if (cur_date.getFullYear() == date.getFullYear()) {
return M + ' ' + j;
}
return M + ' ' + j + ', ' + Y;
}
function getCssProperty(el, prop) {
if (window.getComputedStyle) {
return window.getComputedStyle(el, '').getPropertyValue(prop) || null;
} else if (el.currentStyle) {
return el.currentStyle[prop] || null;
}
return null;
}
function isVisible(el, padding) {
var node = el, val;
var visibility = getCssProperty(node, 'visibility');
if (visibility == 'hidden') return false;
while (node) {
if (node === document.documentElement) break;
var display = getCssProperty(node, 'display');
if (display == 'none') return false;
var opacity = getCssProperty(node, 'opacity');
if (opacity !== null && opacity < 0.1) return false;
node = node.parentNode;
}
if (el.getBoundingClientRect) {
padding = +padding || 0;
var rect = el.getBoundingClientRect();
var html = document.documentElement;
if (rect.bottom < padding ||
rect.right < padding ||
rect.top > (window.innerHeight || html.clientHeight) - padding ||
rect.left > (window.innerWidth || html.clientWidth) - padding) {
return false;
}
}
return true;
}
var TWeb = {
init: function(options) {
options = options || {};
if (!doesSupportThinBoxShadow()) {
$('body').addClass('thin_box_shadow');
}
$('.js-widget_message').each(function() {
TPost.init(this);
});
TWeb.updateServiceDate($('.js-widget_message_wrap'));
if (options.scrollToPost) {
TWeb.highlightPost(options.scrollToPost, true);
} else {
$('.js-widget_message_wrap').last().scrollIntoView({position: 'top'});
}
$('body').removeClass('no_transitions');
$('.js-header_search').on('focus', function() {
$('header.tgme_header').removeClass('search_collapsed');
$(this).select();
});
$('.js-header_search').on('blur', function() {
$('header.tgme_header').addClass('search_collapsed');
});
TWeb.initScroll();
TWeb.initViews();
if (window.matchMedia) {
var darkMedia = window.matchMedia('(prefers-color-scheme: dark)');
TWeb.toggleTheme(darkMedia.matches);
darkMedia.addListener(function(e) {
TWeb.toggleTheme(e.matches);
});
}
if (true) { // wallpaper supported
$('body').addClass('twallpaper');
TWallpaper.init($('#tgme_background').get(0));
$(window).on('focus', function() { // chrome fix
TWallpaper.update();
});
var reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
reduceMotion.addEventListener('change', function() {
TWallpaper.scrollAnimate(!reduceMotion.matches);
});
TWallpaper.scrollAnimate(!reduceMotion.matches);
}
},
toggleTheme: function(dark) {
$('html').toggleClass('theme_dark', dark);
},
initScroll: function() {
var $document = $(document);
$document.on('scroll', function() {
$before = $('.js-messages_more[data-before]');
$after = $('.js-messages_more[data-after]');
var wheight = $(window).height();
var scrollTop = $(window).scrollTop();
if ($before.length) {
var bottom = $before.offset().top + $before.height() - scrollTop;
if (bottom > -wheight * 3) {
TWeb.loadMore($before);
}
}
if ($after.length) {
var top = $after.offset().top - scrollTop;
if (top < wheight * 3) {
TWeb.loadMore($after);
}
}
});
$document.on('click', '.js-messages_more', function() {
var $el = $(this);
TWeb.loadMore($el);
});
},
initViews: function() {
TWeb.viewsMap = {};
TWeb.viewsQueue = [];
TWeb.viewsLastLoad = 0;
var $document = $(document), $window = $(window);
$document.ready(function() {
$window.on('scroll resize', TWeb.checkVisiblePosts);
TWeb.checkVisiblePosts();
});
},
checkVisiblePosts: function() {
$('.js-widget_message[data-view]').each(function() {
if (isVisible(this, 50)) {
var view = this.getAttribute('data-view');
if (view) {
TWeb.addViewToQueue(view);
}
this.removeAttribute('data-view');
}
});
},
addViewToQueue: function(view) {
if (!TWeb.viewsMap[view]) {
TWeb.viewsMap[view] = true;
TWeb.viewsQueue.push(view);
TWeb.sendViewsMaybe();
}
},
sendViewsMaybe: function() {
var now = +(new Date);
if (now - TWeb.viewsLastLoad < 10000 && TWeb.viewsQueue.length < 50) {
return setTimeout(TWeb.sendViewsMaybe, 10000);
}
if (TWeb.viewsQueue.length > 0) {
var views = TWeb.viewsQueue.join(';');
TWeb.viewsQueue = [];
$.ajax('/v/', {type: 'POST', data: {views: views}});
TWeb.viewsLastLoad = now;
}
},
highlightPost: function(post_id, scroll) {
var $postWrap = $('.js-widget_message[data-post="' + post_id + '"]').parents('.js-widget_message_wrap');
if (scroll) {
$postWrap.scrollIntoView({position: 'top'});
}
$postWrap.addClass('prepare_highlight').redraw().addClass('highlight');
setTimeout(function() {
$postWrap.removeClass('highlight');
setTimeout(function() {
$postWrap.removeClass('prepare_highlight');
}, 300);
}, 1500);
},
updateServiceDate: function($wrapEls, skip_first) {
$wrapEls.each(function() {
if (!$(this).data('msg_date')) {
var datetime = $('time[datetime]', this).attr('datetime');
if (datetime) {
var date_formatted = formatDate(datetime);
$('<div class="tgme_widget_message_service_date_wrap"><div class="tgme_widget_message_service_date">' + date_formatted + '</div></div>').appendTo(this);
$(this).data('msg_date', date_formatted);
}
}
});
var len = $wrapEls.size();
for (var i = len - 1; i >= 0; i--) {
var $wrapEl = $wrapEls.eq(i);
var $prevWrapEl = i > 0 ? $wrapEls.eq(i - 1) : null;
if (!$prevWrapEl && skip_first) continue;
var date_visible = !$prevWrapEl || $prevWrapEl.data('msg_date') != $wrapEl.data('msg_date');
$wrapEl.toggleClass('date_visible', date_visible);
}
},
loadMore: function($moreEl, scrollToLast) {
var loading = $moreEl.data('loading');
if (loading) {
return false;
}
var before = $moreEl.attr('data-before');
var after = $moreEl.attr('data-after');
var url = $moreEl.attr('href');
$moreEl.data('loading', true);
$moreEl.addClass('dots-animated');
var time0 = +(new Date);
//console.log('loading...', before, after);
var _load = function(url, before, after) {
$.ajax(url, {
success: function(data) {
var time1 = +(new Date);
//console.log('loaded ' + (time1 - time0) + 'ms');
var $data = $(MakeMbHtml(data));
var $helper = $('<div class="tgme_widget_messages_helper"></div>');
$helper.append($data);
$('.js-message_history').append($helper);
$helper.find('.js-widget_message').each(function() {
TPost.init(this);
});
$helper.remove();
var wrapEls = $data.filter('.js-widget_message_wrap').get();
var time2 = +(new Date);
//console.log('prepared ' + (time2 - time1) + 'ms');
var $moreElWrap = $moreEl.parents('.js-messages_more_wrap');
if (before) {
var firstWrapEl = $moreElWrap.next('.js-widget_message_wrap').get();
var $wrapEls = $(wrapEls.concat(firstWrapEl));
TWeb.updateServiceDate($wrapEls);
var y = $moreElWrap.offset().top + $moreElWrap.outerHeight(true) - $(document).scrollTop();
$data.insertBefore($moreElWrap);
var st = $moreElWrap.offset().top - y;
$moreElWrap.remove();
$(window).scrollTop(st);
} else {
var lastWrapEl = $moreElWrap.prev('.js-widget_message_wrap').get();
var $wrapEls = $(lastWrapEl.concat(wrapEls));
TWeb.updateServiceDate($wrapEls, lastWrapEl.length > 0);
$data.insertBefore($moreElWrap);
$moreElWrap.remove();
}
var time3 = +(new Date);
//console.log('inserted ' + (time3 - time2) + 'ms');
if (scrollToLast) {
//$('#BottomAnchor')[0].scrollIntoView();
$('.tgme_widget_message_wrap').last().scrollIntoView();
}
},
error: function(data) {
var timeout = $moreEl.data('timeout') || 1000;
$moreEl.data('timeout', timeout > 60000 ? timeout : timeout * 2);
setTimeout(function(){ _load(url, before, after); }, timeout);
}
});
};
_load(url, before, after);
},
}
window.TWeb = TWeb;

View File

@ -0,0 +1,808 @@
var RLottie = (function () {
var rlottie = {}, apiInitStarted = false, apiInited = false, initCallbacks = [];
var deviceRatio = window.devicePixelRatio || 1;
var startTime = +(new Date());
function dT() {
return '[' + ((+(new Date()) - startTime)/ 1000.0) + '] ';
}
rlottie.Api = {};
rlottie.players = Object.create(null);;
rlottie.WORKERS_LIMIT = 4;
var reqId = 0;
var mainLoopAf = false;
var mainLoopTo = false;
var mainLoopInited = false;
var checkViewportDate = false;
var lastRenderDate = false;
var userAgent = window.navigator.userAgent;
var isSafari = !!window.safari ||
!!(userAgent && (/\b(iPad|iPhone|iPod)\b/.test(userAgent) || (!!userAgent.match('Safari') && !userAgent.match('Chrome'))));
var isRAF = isSafari;
rlottie.isSafari = isSafari;
function wasmIsSupported() {
try {
if (typeof WebAssembly === 'object' &&
typeof WebAssembly.instantiate === 'function') {
const module = new WebAssembly.Module(Uint8Array.of(
0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00
));
if (module instanceof WebAssembly.Module) {
return new WebAssembly.Instance(module) instanceof WebAssembly.Instance;
}
}
} catch (e) {}
return false;
}
function isSupported() {
return (
wasmIsSupported() &&
typeof Uint8ClampedArray !== 'undefined' &&
typeof Worker !== 'undefined' &&
typeof ImageData !== 'undefined'
);
}
rlottie.isSupported = isSupported();
function mainLoop() {
var key, rlPlayer, delta, rendered;
var isEmpty = true;
var now = +Date.now();
var checkViewport = !checkViewportDate || (now - checkViewportDate) > 1000;
for (key in rlottie.players) {
rlPlayer = rlottie.players[key];
if (rlPlayer &&
rlPlayer.frameCount) {
delta = now - rlPlayer.frameThen;
if (delta > rlPlayer.frameInterval) {
rendered = render(rlPlayer, checkViewport);
if (rendered) {
lastRenderDate = now;
}
}
}
}
// var delay = !lastRenderDate || now - lastRenderDate < 100 ? 16 : 500;
var delay = 16;
if (delay < 20 && isRAF) {
mainLoopAf = requestAnimationFrame(mainLoop)
} else {
mainLoopTo = setTimeout(mainLoop, delay);
}
mainLoopInited = true;
if (checkViewport) {
checkViewportDate = now;
}
}
function setupMainLoop() {
var isEmpty = true, forceRender = false, rlPlayer;
for (key in rlottie.players) {
rlPlayer = rlottie.players[key];
if (rlPlayer &&
rlPlayer.frameCount) {
if (rlPlayer.forceRender) {
forceRender = true;
}
isEmpty = false;
break;
}
}
if (mainLoopInited === isEmpty || forceRender) {
mainLoopAf && cancelAnimationFrame(mainLoopAf);
mainLoopTo && clearTimeout(mainLoopTo);
mainLoopInited = false;
if (!isEmpty) {
if (isRAF) {
mainLoopAf = requestAnimationFrame(mainLoop);
} else {
mainLoopTo = setTimeout(mainLoop, 0);
}
mainLoopInited = true;
}
}
}
function initApi(callback) {
if (apiInited) {
callback && callback();
} else {
callback && initCallbacks.push(callback);
if (!apiInitStarted) {
console.log(dT(), 'tgsticker init');
apiInitStarted = true;
QueryableWorkerProxy.init('/js/tgsticker-worker.js?14', rlottie.WORKERS_LIMIT, function() {
apiInited = true;
for (var i = 0; i < initCallbacks.length; i++) {
initCallbacks[i]();
}
initCallbacks = [];
});
}
}
}
function destroyWorkers() {
QueryableWorkerProxy.destroy();
apiInitStarted = apiInited = false;
}
function initPlayer(el, options) {
if (el.rlPlayer) return;
if (el.tagName.toLowerCase() != 'picture') {
console.warn('only picture tag allowed');
return;
}
options = options || {};
var rlPlayer = el.rlPlayer = {};
rlPlayer.thumb = el.querySelector('img');
var tgs_sources = el.querySelectorAll('source[type="application/x-tgsticker"]');
var multi_source = el.hasAttribute('data-multi-source');
var urls = [], urls_map = {};
for (var i = 0; i < tgs_sources.length; i++) {
var tgs_source = tgs_sources[i];
var url = tgs_source && tgs_source.getAttribute('srcset') || '';
var frames_align = tgs_source && tgs_source.getAttribute('data-frames-align') || '';
if (url && !urls_map[url]) {
urls_map[url] = true;
urls.push({
url: url,
framesAlign: frames_align
});
if (!multi_source) {
break;
}
}
}
if (!urls.length) {
console.warn('picture source application/x-tgsticker not found');
return;
}
var pic_width = el.clientWidth || el.getAttribute('width');
var pic_height = el.clientHeight || el.getAttribute('height');
var curDeviceRatio = options.maxDeviceRatio ? Math.min(options.maxDeviceRatio, deviceRatio) : deviceRatio;
if (!pic_width || !pic_height) {
pic_width = pic_height = 256;
}
rlPlayer.reqId = ++reqId;
rlottie.players[reqId] = rlPlayer;
rlPlayer.el = el;
rlPlayer.frameNo = false;
rlPlayer.nextFrameNo = false;
rlPlayer.frames = {};
rlPlayer.width = Math.trunc(pic_width * curDeviceRatio);
rlPlayer.height = Math.trunc(pic_height * curDeviceRatio);
rlPlayer.workerProxy = QueryableWorkerProxy.create(rlPlayer.reqId, onFrame, onLoaded);
rlPlayer.options = options;
rlPlayer.isVisible = true;
rlPlayer.paused = !!options.noAutoPlay;
rlPlayer.needPlayOnce = !!options.playOnce;
rlPlayer.needPlayUntilEnd = !!options.playUntilEnd;
rlPlayer.repeatCount = false;
rlPlayer.waitForFirstFrame = false;
rlPlayer.stopOnFirstFrame = false;
rlPlayer.stopOnLastFrame = false;
rlPlayer.forcePlayFrames = 0;
rlPlayer.times = [];
rlPlayer.imageData = new ImageData(rlPlayer.width, rlPlayer.height);
rlPlayer.workerProxy.loadFromData(urls, rlPlayer.width, rlPlayer.height);
triggerEvent(rlPlayer.el, 'tg:init');
}
function destroyPlayer(el) {
if (!el.rlPlayer) return;
var rlPlayer = el.rlPlayer;
delete rlottie.players[rlPlayer.reqId];
delete rlPlayer;
setupMainLoop();
}
function render(rlPlayer, checkViewport) {
if (!rlPlayer.canvas ||
rlPlayer.canvas.width == 0 ||
rlPlayer.canvas.height == 0) {
return false;
}
if (!rlPlayer.forceRender) {
var focused = window.isFocused ? isFocused() : document.hasFocus();
if (!focused ||
rlPlayer.paused ||
!rlPlayer.isVisible ||
!rlPlayer.frameCount) {
return false;
}
var isInViewport = rlPlayer.isInViewport;
if (isInViewport === undefined || checkViewport) {
var rect = rlPlayer.el.getBoundingClientRect();
if (rect.bottom < 0 ||
rect.right < 0 ||
rect.top > (window.innerHeight || document.documentElement.clientHeight) ||
rect.left > (window.innerWidth || document.documentElement.clientWidth)) {
isInViewport = false;
} else {
isInViewport = true;
}
rlPlayer.isInViewport = isInViewport;
}
if (!isInViewport) {
return false;
}
}
var frame = rlPlayer.frameQueue.shift();
if (frame !== null) {
doRender(rlPlayer, frame);
var nextFrameNo = rlPlayer.nextFrameNo;
if (rlPlayer.stopOnLastFrame &&
frame.no == rlPlayer.frameCount - 1) {
rlPlayer.stopOnLastFrame = false;
if (!rlPlayer.paused) {
rlPlayer.paused = true;
triggerEvent(rlPlayer.el, 'tg:pause');
}
}
if (rlPlayer.stopOnFirstFrame &&
frame.no == 0) {
if (rlPlayer.waitForFirstFrame) {
rlPlayer.waitForFirstFrame = false;
} else {
rlPlayer.stopOnFirstFrame = false;
if (!rlPlayer.paused) {
rlPlayer.paused = true;
triggerEvent(rlPlayer.el, 'tg:pause');
}
}
}
if (nextFrameNo !== false) {
rlPlayer.nextFrameNo = false;
requestFrame(rlPlayer.reqId, nextFrameNo);
}
}
return true;
}
function doRender(rlPlayer, frame) {
rlPlayer.forceRender = false;
rlPlayer.imageData.data.set(frame.frame);
rlPlayer.context.putImageData(rlPlayer.imageData, 0, 0);
rlPlayer.frameNo = frame.no;
var now = +(new Date());
if (rlPlayer.frameThen) {
rlPlayer.times.push(now - rlPlayer.frameThen)
}
rlPlayer.frameThen = now - (now % rlPlayer.frameInterval);
if (rlPlayer.thumb) {
rlPlayer.el.removeChild(rlPlayer.thumb);
delete rlPlayer.thumb;
}
// console.log(dT(), '['+rlPlayer.reqId+']', 'render frame#'+frame.no);
}
function requestFrame(reqId, frameNo) {
var rlPlayer = rlottie.players[reqId];
var frame = rlPlayer.frames[frameNo];
if (frame) {
// console.log(dT(), '['+reqId+']', 'request frame#'+frameNo+' (cache)');
onFrame(reqId, frameNo, frame);
} else {
// console.log(dT(), '['+reqId+']', 'request frame#'+frameNo+' (worker)');
rlPlayer.workerProxy.renderFrame(frameNo, !isSafari);
}
}
function onFrame(reqId, frameNo, frame) {
var rlPlayer = rlottie.players[reqId];
if (!rlPlayer || !rlPlayer.frames) {
return;
}
if (!rlPlayer.frames[frameNo] &&
(!frameNo || (rlPlayer.options.cachingModulo && ((reqId + frameNo) % rlPlayer.options.cachingModulo)))) {
rlPlayer.frames[frameNo] = new Uint8ClampedArray(frame)
}
var prevNo = frameNo > 0 ? frameNo - 1 : rlPlayer.frameCount - 1;
var lastQueueFrame = rlPlayer.frameQueue.last();
if (lastQueueFrame &&
lastQueueFrame.no != prevNo) {
return;
}
rlPlayer.frameQueue.push({
no: frameNo,
frame: frame
});
var nextFrameNo = ++frameNo;
if (nextFrameNo >= rlPlayer.frameCount) {
nextFrameNo = 0;
if (rlPlayer.times.length) {
// var avg = 0;
// for (var i = 0; i < rlPlayer.times.length; i++) {
// avg += rlPlayer.times[i] / rlPlayer.times.length;
// }
// console.log('avg time: ' + avg + ', ' + rlPlayer.fps);
rlPlayer.times = [];
}
}
if (rlPlayer.frameQueue.needsMore()) {
requestFrame(reqId, nextFrameNo)
} else {
rlPlayer.nextFrameNo = nextFrameNo;
}
}
function onLoaded(reqId, frameCount, fps) {
var rlPlayer = rlottie.players[reqId];
rlPlayer.canvas = document.createElement('canvas');
rlPlayer.canvas.width = rlPlayer.width;
rlPlayer.canvas.height = rlPlayer.height;
rlPlayer.el.appendChild(rlPlayer.canvas);
rlPlayer.context = rlPlayer.canvas.getContext('2d');
rlPlayer.fps = fps;
rlPlayer.frameInterval = 1000 / rlPlayer.fps;
rlPlayer.frameThen = Date.now();
rlPlayer.frameCount = frameCount;
rlPlayer.forceRender = true;
rlPlayer.frameQueue = new FrameQueue(fps / 4);
setupMainLoop();
requestFrame(reqId, 0);
triggerEvent(rlPlayer.el, 'tg:load');
if (frameCount > 0) {
if (rlPlayer.needPlayOnce) {
delete rlPlayer.needPlayOnce;
delete rlPlayer.needPlayUntilEnd;
rlPlayer.paused = false;
rlPlayer.stopOnFirstFrame = true;
rlPlayer.stopOnLastFrame = false;
if (rlPlayer.frameNo === false ||
rlPlayer.frameNo > 0) {
rlPlayer.waitForFirstFrame = true;
}
} else if (rlPlayer.needPlayUntilEnd) {
delete rlPlayer.needPlayOnce;
delete rlPlayer.needPlayUntilEnd;
rlPlayer.paused = false;
rlPlayer.stopOnFirstFrame = false;
rlPlayer.stopOnLastFrame = true;
}
}
if (!rlPlayer.paused) {
triggerEvent(rlPlayer.el, 'tg:play');
}
}
rlottie.init = function(el, options) {
if (!rlottie.isSupported) {
return false;
}
initApi(function() {
el && initPlayer(el, options);
});
}
rlottie.destroy = function(el) {
destroyPlayer(el);
}
rlottie.playOnce = function(el) {
if (el && el.rlPlayer) {
var rlPlayer = el.rlPlayer;
if (rlPlayer.frameCount > 0) {
rlPlayer.stopOnFirstFrame = true;
rlPlayer.stopOnLastFrame = false;
if (rlPlayer.frameNo > 0) {
rlPlayer.waitForFirstFrame = true;
}
if (rlPlayer.paused) {
rlPlayer.paused = false;
triggerEvent(el, 'tg:play');
}
} else {
rlPlayer.needPlayOnce = true;
}
}
}
rlottie.playUntilEnd = function(el) {
if (el && el.rlPlayer) {
var rlPlayer = el.rlPlayer;
if (rlPlayer.frameCount > 0) {
rlPlayer.stopOnFirstFrame = false;
rlPlayer.stopOnLastFrame = true;
if (rlPlayer.paused) {
rlPlayer.paused = false;
triggerEvent(el, 'tg:play');
}
} else {
rlPlayer.needPlayUntilEnd = true;
}
}
}
rlottie.play = function(el, reset) {
if (el && el.rlPlayer) {
if (reset) {
rlottie.reset(el);
}
el.rlPlayer.paused = false;
}
}
rlottie.pause = function(el) {
if (el && el.rlPlayer) {
el.rlPlayer.paused = true;
}
}
rlottie.reset = function(el) {
if (el && el.rlPlayer) {
var rlPlayer = el.rlPlayer;
rlPlayer.frameQueue.clear();
rlPlayer.forceRender = true;
requestFrame(rlPlayer.reqId, 0);
setupMainLoop();
}
}
rlottie.destroyWorkers = function() {
destroyWorkers();
}
return rlottie;
}());
var QueryableWorkerProxy = (function() {
var workerproxy = {};
var proxyId = 0;
var wReqId = 0;
var rObjs = {};
var wrMap = {};
var proxies = {};
var rlottieWorkers = [], curWorkerNum = 0;
var startTime = +(new Date());
function dT() {
return '[' + ((+(new Date()) - startTime)/ 1000.0) + '] ';
}
function Proxy(playerId, onFrame, onLoaded) {
this.proxyId = ++proxyId;
this.playerId = playerId;
this.onFrame = onFrame;
this.onLoaded = onLoaded;
this.items = [];
this.itemsMap = {};
proxies[this.proxyId] = this;
return this;
};
Proxy.prototype.loadFromData = function(urls, width, height) {
if (this.items.length > 0) {
console.warn('already loaded');
return;
}
this.clampedSize = width * height * 4;
for (var i = 0; i < urls.length; i++) {
var url = urls[i];
var _wReqId = ++wReqId;
var worker = rlottieWorkers[curWorkerNum++];
if (curWorkerNum >= rlottieWorkers.length) {
curWorkerNum = 0;
}
worker.sendQuery('loadFromData', _wReqId, url.url, width, height);
var item = {
reqId: _wReqId,
worker: worker,
url: url.url,
loaded: false,
clamped: new Uint8ClampedArray(this.clampedSize),
frameLoaded: {}
};
if (url.framesAlign) {
item.framesAlign = url.framesAlign;
}
this.items.push(item);
this.itemsMap[_wReqId] = item;
wrMap[_wReqId] = this.proxyId;
}
if (this.items.length > 1) {
this.canvas = document.createElement('canvas');
this.canvas.width = width;
this.canvas.height = height;
this.context = this.canvas.getContext('2d');
this.imageData = new ImageData(width, height);
}
};
Proxy.prototype.renderFrame = function(frameNo, need_clamped) {
for (var i = 0; i < this.items.length; i++) {
var item = this.items[i];
var realFrameNo = frameNo;
if (item.framesAlign == 'right') {
realFrameNo = frameNo - (this.frameCount - item.frameCount);
}
if (need_clamped) {
if(!item.clamped.length) { // fix detached
item.clamped = new Uint8ClampedArray(this.clampedSize);
}
item.worker.sendQuery('renderFrame', item.reqId, realFrameNo, item.clamped);
} else {
item.worker.sendQuery('renderFrame', item.reqId, realFrameNo);
}
// console.log(dT(), '['+this.playerId+'.'+item.reqId+']', 'request frame#'+frameNo+' (worker)');
}
};
function onFrame(wReqId, realFrameNo, frame) {
var proxyId = wrMap[wReqId];
var proxy = proxies[proxyId];
var item = proxy.itemsMap[wReqId];
var frameNo = realFrameNo;
if (item.framesAlign == 'right') {
frameNo = realFrameNo + (proxy.frameCount - item.frameCount);
}
// console.log(dT(), '['+proxy.playerId+'.'+item.reqId+']', 'onframe#'+frameNo+' (worker)');
item.frameLoaded[frameNo] = frame;
var finished = true;
for (var i = 0; i < proxy.items.length; i++) {
var item = proxy.items[i];
var loadedFrame = item.frameLoaded[frameNo];
if (!loadedFrame) {
finished = false;
break;
}
}
if (finished) {
if (proxy.items.length == 1) {
var loadedFrame = proxy.items[0].frameLoaded[frameNo];
proxy.onFrame(proxy.playerId, frameNo, loadedFrame);
delete proxy.items[0].frameLoaded[frameNo];
} else {
var promises = [];
for (var i = 0; i < proxy.items.length; i++) {
var item = proxy.items[i];
var loadedFrame = item.frameLoaded[frameNo];
proxy.imageData.data.set(loadedFrame);
var promise = createImageBitmap(proxy.imageData);
promises.push(promise);
delete item.frameLoaded[frameNo];
}
Promise.all(promises).then(function(bitmaps) {
proxy.context.clearRect(0, 0, proxy.canvas.width, proxy.canvas.height);
for (var i = 0; i < bitmaps.length; i++) {
proxy.context.drawImage(bitmaps[i], 0, 0);
}
var imageData = proxy.context.getImageData(0, 0, proxy.canvas.width, proxy.canvas.height);
proxy.onFrame(proxy.playerId, frameNo, imageData.data);
});
}
} else {
delete frameDatas;
}
}
function onLoaded(wReqId, frameCount, fps) {
var proxyId = wrMap[wReqId];
var proxy = proxies[proxyId];
var item = proxy.itemsMap[wReqId];
item.loaded = true;
item.frameCount = frameCount;
item.fps = fps;
var finished = true;
frameCount = null; fps = null;
for (var i = 0; i < proxy.items.length; i++) {
var item = proxy.items[i];
if (!item.framesAlign) {
if (frameCount === null) {
frameCount = item.frameCount;
} else if (frameCount !== false && frameCount !== item.frameCount) {
frameCount = false;
}
}
if (fps === null) {
fps = item.fps;
} else if (fps !== false && fps !== item.fps) {
fps = false;
}
if (!item.loaded) {
finished = false;
break;
}
}
if (finished) {
if (frameCount === null) {
console.warn('Frame count not defined'); return;
}
if (frameCount === false) {
console.warn('Frame count is different'); return;
}
if (fps === null) {
console.warn('FPS not defined'); return;
}
if (fps === false) {
console.warn('FPS is different'); return;
}
proxy.frameCount = frameCount;
proxy.fps = fps;
proxy.onLoaded(proxy.playerId, frameCount, fps);
}
}
workerproxy.init = function(worker_url, workers_limit, callback) {
var workersRemain = workers_limit;
var firstWorker = rlottieWorkers[0] = new QueryableWorker(worker_url);
firstWorker.addListener('ready', function () {
console.log(dT(), 'worker #0 ready');
firstWorker.addListener('frame', onFrame);
firstWorker.addListener('loaded', onLoaded);
--workersRemain;
if (!workersRemain) {
console.log(dT(), 'workers ready');
callback && callback();
} else {
for (var workerNum = 1; workerNum < workers_limit; workerNum++) {
(function(workerNum) {
var rlottieWorker = rlottieWorkers[workerNum] = new QueryableWorker(worker_url);
rlottieWorker.addListener('ready', function () {
console.log(dT(), 'worker #' + workerNum + ' ready');
rlottieWorker.addListener('frame', onFrame);
rlottieWorker.addListener('loaded', onLoaded);
--workersRemain;
if (!workersRemain) {
console.log(dT(), 'workers ready');
callback && callback();
}
});
})(workerNum);
}
}
});
};
workerproxy.create = function(playerId, onFrame, onLoaded) {
return new Proxy(playerId, onFrame, onLoaded);
};
workerproxy.destroy = function() {
for (var workerNum = 0; workerNum < rlottieWorkers.length; workerNum++) {
rlottieWorkers[workerNum].terminate();
console.log('worker #' + workerNum + ' terminated');
}
console.log('workers destroyed');
rlottieWorkers = [];
};
return workerproxy;
}());
function QueryableWorker(url, defaultListener, onError) {
var instance = this;
var worker = new Worker(url);
var listeners = {};
this.defaultListener = defaultListener || function() {};
if (onError) {worker.onerror = onError;}
this.postMessage = function(message) {
worker.postMessage(message);
}
this.terminate = function() {
worker.terminate();
}
this.addListener = function(name, listener) {
listeners[name] = listener;
}
this.removeListener = function(name) {
delete listeners[name];
}
/*
This functions takes at least one argument, the method name we want to query.
Then we can pass in the arguments that the method needs.
*/
this.sendQuery = function(queryMethod) {
if (arguments.length < 1) {
throw new TypeError('QueryableWorker.sendQuery takes at least one argument');
return;
}
var queryMethod = arguments[0];
var args = Array.prototype.slice.call(arguments, 1);
if (RLottie.isSafari) {
worker.postMessage({
'queryMethod': queryMethod,
'queryMethodArguments': args
});
} else {
var transfer = [];
for(var i = 0; i < args.length; i++) {
if(args[i] instanceof ArrayBuffer) {
transfer.push(args[i]);
}
if(args[i].buffer && args[i].buffer instanceof ArrayBuffer) {
transfer.push(args[i].buffer);
}
}
worker.postMessage({
'queryMethod': queryMethod,
'queryMethodArguments': args
}, transfer);
}
}
worker.onmessage = function(event) {
if (event.data instanceof Object &&
event.data.hasOwnProperty('queryMethodListener') &&
event.data.hasOwnProperty('queryMethodArguments')) {
listeners[event.data.queryMethodListener].apply(instance, event.data.queryMethodArguments);
} else {
this.defaultListener.call(instance, event.data);
}
}
}
function FrameQueue(maxLength) {
this.queue = [];
this.maxLength = maxLength;
}
FrameQueue.prototype.needsMore = function frameQueueNeedsMore() {
return this.queue.length < this.maxLength;
}
FrameQueue.prototype.empty = function frameQueueEmpty() {
return !this.queue.length;
}
FrameQueue.prototype.notEmpty = function frameQueueEmpty() {
return this.queue.length > 0;
}
FrameQueue.prototype.push = function frameQueuePush(element) {
return this.queue.push(element);
}
FrameQueue.prototype.shift = function frameQueueShift() {
return this.queue.length ? this.queue.shift() : null;
}
FrameQueue.prototype.last = function frameQueueLast(element) {
return this.queue.length ? this.queue[this.queue.length - 1] : null;
}
FrameQueue.prototype.clear = function frameQueueClear() {
this.queue = [];
return true;
}
if (!this.CustomEvent || typeof this.CustomEvent === "object") {
(function() {
this.CustomEvent = function CustomEvent(type, eventInitDict) {
var event;
eventInitDict = eventInitDict || {bubbles: false, cancelable: false, detail: undefined};
try {
event = document.createEvent('CustomEvent');
event.initCustomEvent(type, eventInitDict.bubbles, eventInitDict.cancelable, eventInitDict.detail);
} catch (error) {
event = document.createEvent('Event');
event.initEvent(type, eventInitDict.bubbles, eventInitDict.cancelable);
event.detail = eventInitDict.detail;
}
return event;
};
})();
}
function triggerEvent(el, event_type, init_dict) {
var event = new CustomEvent(event_type, init_dict);
el.dispatchEvent(event);
}

1
public/MBViewer/js/tgwallpaper.min.js vendored Normal file
View File

@ -0,0 +1 @@
var TWallpaper=function(){function x(a){for(var b=[].concat(G);0<a;)b.push(b.shift()),a--;a=[];for(var c=0;c<b.length;c+=2)a.push(b[c]);return a}function B(a,b){b%=90;var c=x(a%p);if(b){var d=x(++a%p);return[{x:c[0].x+(d[0].x-c[0].x)/90*b,y:c[0].y+(d[0].y-c[0].y)/90*b},{x:c[1].x+(d[1].x-c[1].x)/90*b,y:c[1].y+(d[1].y-c[1].y)/90*b},{x:c[2].x+(d[2].x-c[2].x)/90*b,y:c[2].y+(d[2].y-c[2].y)/90*b},{x:c[3].x+(d[3].x-c[3].x)/90*b,y:c[3].y+(d[3].y-c[3].y)/90*b}]}return c}function H(a){for(l+=a;90<=l;)l-=90,g++,g>=p&&(g-=p);for(;0>l;)l+=90,g--,0>g&&(g+=p)}function I(a){C+=a.deltaY;D||(requestAnimationFrame(P),D=!0)}function P(){var a=C/50;C%=50;if(a=0<a?Math.floor(a):Math.ceil(a))H(a),a=B(g,l),y(z(a));D=!1}function Q(){if(0<A.length){var a=A.shift();y(a)}else clearInterval(E)}function z(a){for(var b=f._hctx.createImageData(50,50),c=b.data,d=0,q=0;50>q;q++)for(var h=q/50-.5,F=h*h,v=0;50>v;v++){var m=v/50-.5,e=.35*Math.sqrt(m*m+F);e=e*e*6.4;var r=Math.sin(e),w=Math.cos(e);e=Math.max(0,Math.min(1,.5+m*w-h*r));m=Math.max(0,Math.min(1,.5+m*r+h*w));for(var J=w=r=0,K=0,t=0;t<u.length;t++){var k=e-a[t].x,L=m-a[t].y;k=Math.max(0,.9-Math.sqrt(k*k+L*L));k*=k*k*k;r+=k;w+=k*u[t].r/255;J+=k*u[t].g/255;K+=k*u[t].b/255}c[d++]=w/r*255;c[d++]=J/r*255;c[d++]=K/r*255;c[d++]=255}return b}function y(a){f._hctx.putImageData(a,0,0);f._ctx.drawImage(f._hc,0,0,50,50)}function M(){var a=+Date.now();!document.hasFocus()||a-N<R||(N=a,H(1),a=B(g,l),y(z(a)));O=requestAnimationFrame(M)}var g=0,l=0,N=0,R=1E3/15,A=[],E=null,O=null,u=[],n=[0,.25,.5,.75,1,1.5,2,2.5,3,3.5,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,18.3,18.6,18.9,19.2,19.5,19.8,20.1,20.4,20.7,21,21.3,21.6,21.9,22.2,22.5,22.8,23.1,23.4,23.7,24,24.3,24.6,24.9,25.2,25.5,25.8,26.1,26.3,26.4,26.5,26.6,26.7,26.8,26.9,27],G=[{x:.8,y:.1},{x:.6,y:.2},{x:.35,y:.25},{x:.25,y:.6},{x:.2,y:.9},{x:.4,y:.8},{x:.65,y:.75},{x:.75,y:.4}],p=G.length,D=!1,C=0,f={init:function(a){u=[];var b=a.getAttribute("data-colors")||"";b&&(b=b.split(","));for(var c=0;c<b.length;c++){var d=u,q=d.push;var h=(h=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(b[c]))?{r:parseInt(h[1],16),g:parseInt(h[2],16),b:parseInt(h[3],16)}:null;q.call(d,h)}f._hc||(f._hc=document.createElement("canvas"),f._hc.width=50,f._hc.height=50,f._hctx=f._hc.getContext("2d"));f._canvas=a;f._ctx=f._canvas.getContext("2d");f.update()},update:function(){var a=B(g,l);y(z(a))},toNextPosition:function(){clearInterval(E);A=[];var a=x(g%p);g++;var b=x(g%p),c=(b[0].x-a[0].x)/27,d=(b[0].y-a[0].y)/27,q=(b[1].x-a[1].x)/27,h=(b[1].y-a[1].y)/27,F=(b[2].x-a[2].x)/27,v=(b[2].y-a[2].y)/27,m=(b[3].x-a[3].x)/27;b=(b[3].y-a[3].y)/27;for(var e=0;60>e;e++)A.push(z([{x:a[0].x+c*n[e],y:a[0].y+d*n[e]},{x:a[1].x+q*n[e],y:a[1].y+h*n[e]},{x:a[2].x+F*n[e],y:a[2].y+v*n[e]},{x:a[3].x+m*n[e],y:a[3].y+b*n[e]}]));E=setInterval(Q,1E3/30)},animate:function(a){a?M():cancelAnimationFrame(O)},scrollAnimate:function(a){a?document.addEventListener("wheel",I):document.removeEventListener("wheel",I)}};return f}();

File diff suppressed because it is too large Load Diff

View File

@ -33,6 +33,8 @@ TODO:
* compatibility build / add polyfills
* multilanguage?
* gif encoding without webserver (without ES import)
* APNG encoding, if it works
* allow copying the JSON (and optionally reuploading images? probably not needed tho) when importing existing Maunium packs
-->
<div id="Main" hidden="true">
@ -849,6 +851,7 @@ TODO:
`${Defaults.appIdentity}`,
`${Defaults.appIdentity}/${Defaults.appInterface}`,
],
creatorUserId: GetMatrixUserTag(State.account),
},
sender: GetMatrixUserTag(State.account),
state_key: "stickerpicker",