1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-08-03 00:18:31 +00:00
This release implements a massive change to how link tool-tips and embeds work. They might act up a bit while we get the new back-end installed and tweaked.

* Added: Options to use custom formats for dates and times, under `Appearance > Localization`.
* Added: Options to change the colors of tool-tips.
* Changed: Completely rewrite how link information is formatted together with a complete rewrite of the link information service.
* Changed: The FFZ Control Center now remembers you previously open settings if you reload the page.
* Fixed: Update chat lines when i18n data loads.
* Fixed: i18n not correctly formatting certain numbers.
* Fixed: Theater mode automatically enabling on user home pages. (Closes #866)
* Fixed: Theater metadata overlapping chat with Swap Sidebars enabled. (Closes #835)
* API Added: New icons: `location`, `link`, and `volume-off`
* API Fixed: `createElement` not properly handling `<video>` related attributes.
This commit is contained in:
SirStendec 2020-08-04 18:26:11 -04:00
parent eec65551fb
commit 6310a2ed49
49 changed files with 2432 additions and 884 deletions

View file

@ -20,7 +20,11 @@ const EMOTE_CLASS = 'chat-image chat-line__message--emote',
// Links
// ============================================================================
const TOOLTIP_VERSION = 4;
function datasetBool(value) {
return value == null ? null : value === 'true';
}
const TOOLTIP_VERSION = 5;
export const Links = {
type: 'link',
@ -47,60 +51,94 @@ export const Links = {
if ( target.dataset.isMail === 'true' )
return [this.i18n.t('tooltip.email-link', 'E-Mail {address}', {address: target.textContent})];
const url = target.dataset.url || target.href;
const url = target.dataset.url || target.href,
show_images = datasetBool(target.dataset.forceMedia) ?? this.context.get('tooltip.link-images'),
show_unsafe = datasetBool(target.dataset.forceUnsafe) ?? this.context.get('tooltip.link-nsfw-images');
return this.get_link_info(url).then(data => {
return Promise.all([
import(/* webpack-chunk-name: 'rich_tokens' */ 'utilities/rich_tokens'),
this.get_link_info(url)
]).then(([rich_tokens, data]) => {
if ( ! data || (data.v || 1) > TOOLTIP_VERSION )
return '';
let content = data.content || data.html || '';
const ctx = {
tList: (...args) => this.i18n.tList(...args),
i18n: this.i18n,
allow_media: show_images,
allow_unsafe: show_unsafe,
onload: tip.update
};
// TODO: Replace timestamps.
if ( data.urls && data.urls.length > 1 )
content += (content.length ? '<hr>' : '') +
sanitize(this.i18n.t(
'tooltip.link-destination',
'Destination: {url}',
{url: data.urls[data.urls.length-1][1]}
));
if ( data.unsafe ) {
const reasons = Array.from(new Set(data.urls.map(x => x[2]).filter(x => x))).join(', ');
content = this.i18n.t(
'tooltip.link-unsafe',
"Caution: This URL is on Google's Safe Browsing List for: {reasons}",
{reasons: sanitize(reasons.toLowerCase())}
) + (content.length ? `<hr>${content}` : '');
let content;
if ( tip.element ) {
tip.element.classList.add('ffz-rich-tip');
tip.element.classList.add('tw-align-left');
}
const show_image = this.context.get('tooltip.link-images') && (data.image_safe || this.context.get('tooltip.link-nsfw-images'));
if ( data.full ) {
content = rich_tokens.renderTokens(data.full, createElement, ctx);
if ( show_image ) {
if ( data.image && ! data.image_iframe )
content = `<img class="preview-image" src="${sanitize(data.image)}">${content}`
} else {
if ( data.short ) {
content = rich_tokens.renderTokens(data.short, createElement, ctx);
} else
content = this.i18n.t('card.empty', 'No data was returned.');
}
setTimeout(() => {
if ( tip.element ) {
for(const el of tip.element.querySelectorAll('img'))
el.addEventListener('load', tip.update);
if ( ! data.urls )
return content;
for(const el of tip.element.querySelectorAll('video'))
el.addEventListener('loadedmetadata', tip.update);
}
const url_table = [];
for(let i=0; i < data.urls.length; i++) {
const url = data.urls[i];
url_table.push(<tr>
<td>{this.i18n.formatNumber(i + 1)}.</td>
<td class="tw-c-text-alt-2 tw-pd-x-05 tw-word-break-all">{url.url}</td>
<td>{url.flags ? url.flags.map(flag => <span class="tw-pill">{flag.toLowerCase()}</span>) : null}</td>
</tr>);
}
let url_notice;
if ( data.unsafe ) {
const reasons = Array.from(new Set(data.urls.map(url => url.flags).flat())).join(', ');
url_notice = (<div class="ffz-i-attention">
{this.i18n.tList(
'tooltip.link-unsafe',
"Caution: This URL is on Google's Safe Browsing List for: {reasons}",
{reasons: reasons.toLowerCase()}
)}
</div>);
} else if ( data.urls.length > 1 )
url_notice = this.i18n.t('tooltip.link-destination', 'Destination: {url}', {
url: data.urls[data.urls.length-1].url
});
} else if ( content.length )
content = content.replace(/<!--MS-->.*<!--ME-->/g, '');
if ( data.tooltip_class )
tip.element.classList.add(data.tooltip_class);
content = (<div>
<div class="ffz--shift-hide">
{content}
{url_notice ? <div class="tw-mg-t-05 tw-border-t tw-pd-t-05 tw-align-center">
{url_notice}
<div class=" tw-font-size-8">
{this.i18n.t('tooltip.shift-detail', '(Shift for Details)')}
</div>
</div> : null}
</div>
<div class="ffz--shift-show tw-align-left">
<div class="tw-semibold tw-mg-b-05 tw-align-center">
{this.i18n.t('tooltip.link.urls', 'Visited URLs')}
</div>
<table>{url_table}</table>
</div>
</div>);
return content;
}).catch(error =>
sanitize(this.i18n.t('tooltip.error', 'An error occurred. ({error})', {error}))
);
}).catch(error => {
console.error(error);
return sanitize(this.i18n.t('tooltip.error', 'An error occurred. ({error})', {error}))
});
},
process(tokens) {