mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-10-17 08:21:59 +00:00
The Great Webpack Update.
* Update to version 4 of webpack. * For that matter, update *every dependency* to the latest available version. * Remove the babel build target for Edge, as it doesn't seem to be necessary with webpack 4 and tenser. * Add support for optional chaining and nullish coalescing via Babel transformations. * Update the clips domain version to work better. Or at all, really. * Remove unused code from i18n. * Remove the last `<style>` from vue component files. They don't work that way now anyways. * Fix a bug in Raven's report handler. * Fix a bug with the menu button in browsers that don't understand `:scope` within `querySelector()`.
This commit is contained in:
parent
567708b7f1
commit
014eb203c3
31 changed files with 3106 additions and 5715 deletions
|
@ -7,15 +7,13 @@
|
|||
|
||||
const DEBUG = localStorage.ffzDebugMode == 'true' && document.body.classList.contains('ffz-dev') && ! window.Ember,
|
||||
SERVER = DEBUG ? '//localhost:8000' : '//cdn.frankerfacez.com',
|
||||
BABEL = /Edge/.test(window.navigator.userAgent) ? 'babel/' : '',
|
||||
CLIPS = /clips\.twitch\.tv/.test(location.hostname) ? 'clips/' : '',
|
||||
FLAVOR = window.Ember ? 'umbral' : 'avalon',
|
||||
|
||||
script = document.createElement('script');
|
||||
|
||||
script.id = 'ffz-script';
|
||||
script.async = true;
|
||||
script.crossOrigin = 'anonymous';
|
||||
script.src = `${SERVER}/script/${CLIPS}${BABEL}${FLAVOR}.js?_=${Date.now()}`;
|
||||
script.src = `${SERVER}/script/${CLIPS}avalon.js?_=${Date.now()}`;
|
||||
document.head.appendChild(script);
|
||||
})();
|
|
@ -22,7 +22,7 @@ const OVERRIDE_COOKIE = 'experiment_overrides',
|
|||
// We want to import this so that the file is included in the output.
|
||||
// We don't load using this because we might want a newer file from the
|
||||
// server.
|
||||
import EXPERIMENTS from 'file-loader?name=[name].[hash].[ext]!./experiments.json'; // eslint-disable-line no-unused-vars
|
||||
import EXPERIMENTS from './experiments.json'; // eslint-disable-line no-unused-vars
|
||||
|
||||
|
||||
// ============================================================================
|
||||
|
|
194
src/i18n.js
194
src/i18n.js
|
@ -12,7 +12,6 @@ import Module from 'utilities/module';
|
|||
|
||||
import NewTransCore from 'utilities/translation-core';
|
||||
|
||||
|
||||
const FACES = ['(・`ω´・)', ';;w;;', 'owo', 'ono', 'oAo', 'oxo', 'ovo;', 'UwU', '>w<', '^w^', '> w >', 'v.v'],
|
||||
|
||||
transformText = (ast, fn) => {
|
||||
|
@ -428,203 +427,12 @@ export class TranslationManager extends Module {
|
|||
}
|
||||
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// TranslationCore
|
||||
// ============================================================================
|
||||
|
||||
const REPLACE = String.prototype.replace; /*,
|
||||
SPLIT = String.prototype.split;
|
||||
|
||||
const DEFAULT_FORMATTERS = {
|
||||
en_plural: n => n !== 1 ? 's' : '',
|
||||
number: (n, locale) => n.toLocaleString(locale)
|
||||
}
|
||||
|
||||
|
||||
export default class TranslationCore {
|
||||
constructor(options) {
|
||||
options = options || {};
|
||||
this.warn = options.warn;
|
||||
this.phrases = new Map;
|
||||
this.extend(options.phrases);
|
||||
this.locale = options.locale || 'en';
|
||||
this.defaultLocale = options.defaultLocale || this.locale;
|
||||
this.transformation = null;
|
||||
|
||||
const allowMissing = options.allowMissing ? transformPhrase : null;
|
||||
this.onMissingKey = typeof options.onMissingKey === 'function' ? options.onMissingKey : allowMissing;
|
||||
this.transformPhrase = typeof options.transformPhrase === 'function' ? options.transformPhrase : transformPhrase;
|
||||
this.transformList = typeof options.transformList === 'function' ? options.transformList : transformList;
|
||||
this.delimiter = options.delimiter || /\s*\|\|\|\|\s/;
|
||||
this.tokenRegex = options.tokenRegex || /%\{(.*?)(?:\|(.*?))?\}/g;
|
||||
this.formatters = Object.assign({}, DEFAULT_FORMATTERS, options.formatters || {});
|
||||
}
|
||||
|
||||
|
||||
formatNumber(value) {
|
||||
return value.toLocaleString(this.locale);
|
||||
}
|
||||
|
||||
|
||||
extend(phrases, prefix) {
|
||||
const added = [];
|
||||
for(const key in phrases)
|
||||
if ( has(phrases, key) ) {
|
||||
let phrase = phrases[key];
|
||||
const pref_key = prefix ? key === '_' ? prefix : `${prefix}.${key}` : key;
|
||||
|
||||
if ( typeof phrase === 'object' )
|
||||
added.push(...this.extend(phrase, pref_key));
|
||||
else {
|
||||
if ( typeof phrase === 'string' && phrase.indexOf(this.delimiter) !== -1 )
|
||||
phrase = SPLIT.call(phrase, this.delimiter);
|
||||
this.phrases.set(pref_key, phrase);
|
||||
added.push(pref_key);
|
||||
}
|
||||
}
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
unset(phrases, prefix) {
|
||||
if ( typeof phrases === 'string' )
|
||||
phrases = [phrases];
|
||||
|
||||
const keys = Array.isArray(phrases) ? phrases : Object.keys(phrases);
|
||||
for(const key of keys) {
|
||||
const pref_key = prefix ? `${prefix}.${key}` : key;
|
||||
const phrase = phrases[key];
|
||||
if ( typeof phrase === 'object' )
|
||||
this.unset(phrase, pref_key);
|
||||
else
|
||||
this.phrases.delete(pref_key);
|
||||
}
|
||||
}
|
||||
|
||||
has(key) {
|
||||
return this.phrases.has(key);
|
||||
}
|
||||
|
||||
set(key, phrase) {
|
||||
if ( typeof phrase === 'string' && phrase.indexOf(this.delimiter) !== -1 )
|
||||
phrase = SPLIT.call(phrase, this.delimiter);
|
||||
|
||||
this.phrases.set(key, phrase);
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.phrases.clear();
|
||||
}
|
||||
|
||||
replace(phrases) {
|
||||
this.clear();
|
||||
this.extend(phrases);
|
||||
}
|
||||
|
||||
preT(key, phrase, options, use_default) {
|
||||
const opts = options == null ? {} : options;
|
||||
let p, locale;
|
||||
|
||||
if ( use_default ) {
|
||||
p = phrase;
|
||||
locale = this.defaultLocale;
|
||||
|
||||
} else if ( key === undefined && phrase ) {
|
||||
p = phrase;
|
||||
locale = this.defaultLocale;
|
||||
if ( this.warn )
|
||||
this.warn(`Translation key not generated with phrase "${phrase}"`);
|
||||
|
||||
} else if ( this.phrases.has(key) ) {
|
||||
p = this.phrases.get(key);
|
||||
locale = this.locale;
|
||||
} else if ( phrase ) {
|
||||
if ( this.warn && this.locale !== this.defaultLocale )
|
||||
this.warn(`Missing translation for key "${key}" in locale "${this.locale}"`);
|
||||
|
||||
p = phrase;
|
||||
locale = this.defaultLocale;
|
||||
} else if ( this.onMissingKey )
|
||||
return this.onMissingKey(key, opts, this.locale, this.tokenRegex, this.formatters);
|
||||
else {
|
||||
if ( this.warn )
|
||||
this.warn(`Missing translation for key "${key}" in locale "${this.locale}"`);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
if ( this.transformation )
|
||||
p = this.transformation(key, p, opts, locale, this.tokenRegex);
|
||||
|
||||
return [p, opts, locale];
|
||||
}
|
||||
|
||||
t(key, phrase, options, use_default) {
|
||||
const [p, opts, locale] = this.preT(key, phrase, options, use_default);
|
||||
|
||||
return this.transformPhrase(p, opts, locale, this.tokenRegex, this.formatters);
|
||||
}
|
||||
|
||||
tList(key, phrase, options, use_default) {
|
||||
const [p, opts, locale] = this.preT(key, phrase, options, use_default);
|
||||
|
||||
return this.transformList(p, opts, locale, this.tokenRegex, this.formatters);
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// Transformations
|
||||
// ============================================================================
|
||||
|
||||
const DOLLAR_REGEX = /\$/g;
|
||||
|
||||
export function transformList(phrase, substitutions, locale, token_regex, formatters) {
|
||||
const is_array = Array.isArray(phrase);
|
||||
if ( substitutions == null )
|
||||
return is_array ? phrase[0] : phrase;
|
||||
|
||||
let p = phrase;
|
||||
const options = typeof substitutions === 'number' ? {count: substitutions} : substitutions;
|
||||
|
||||
if ( is_array )
|
||||
p = p[0];
|
||||
|
||||
const result = [];
|
||||
|
||||
token_regex.lastIndex = 0;
|
||||
let idx = 0, match;
|
||||
|
||||
while((match = token_regex.exec(p))) {
|
||||
const nix = match.index,
|
||||
arg = match[1],
|
||||
fmt = match[2];
|
||||
|
||||
if ( nix !== idx )
|
||||
result.push(p.slice(idx, nix));
|
||||
|
||||
let val = get(arg, options);
|
||||
|
||||
if ( val != null ) {
|
||||
const formatter = formatters[fmt];
|
||||
if ( typeof formatter === 'function' )
|
||||
val = formatter(val, locale, options);
|
||||
else if ( typeof val === 'string' )
|
||||
val = REPLACE.call(val, DOLLAR_REGEX, '$$');
|
||||
|
||||
result.push(val);
|
||||
}
|
||||
|
||||
idx = nix + match[0].length;
|
||||
}
|
||||
|
||||
if ( idx < p.length )
|
||||
result.push(p.slice(idx));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const REPLACE = String.prototype.replace;
|
||||
|
||||
export function transformPhrase(phrase, substitutions, locale, token_regex, formatters) {
|
||||
const is_array = Array.isArray(phrase);
|
||||
|
|
|
@ -151,7 +151,7 @@ ${typeof x[1] === 'string' ? x[1] : JSON.stringify(x[1], null, 4)}`
|
|||
FrankerFaceZ.Logger = Logger;
|
||||
|
||||
const VER = FrankerFaceZ.version_info = {
|
||||
major: 4, minor: 5, revision: 2,
|
||||
major: 4, minor: 5, revision: 3,
|
||||
commit: __git_commit__,
|
||||
build: __webpack_hash__,
|
||||
toString: () =>
|
||||
|
|
|
@ -120,26 +120,4 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.ffz--example-report {
|
||||
div {
|
||||
max-height: 30rem;
|
||||
overflow-y: auto;
|
||||
|
||||
code {
|
||||
font-family: monospace;
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ffz--report-upload {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 3rem;
|
||||
}
|
||||
</style>
|
||||
</script>
|
|
@ -176,7 +176,7 @@ export default class RavenLogger extends Module {
|
|||
const exc = data.exception && data.exception.values[0];
|
||||
|
||||
// We don't want any of Sentry's junk.
|
||||
if ( data.message && data.messages.includes('raven-js/') || (exc && JSON.stringify(exc).includes('raven-js/')) )
|
||||
if ( data.message && data.message.includes('raven-js/') || (exc && JSON.stringify(exc).includes('raven-js/')) )
|
||||
return false;
|
||||
|
||||
// We don't want any of Mozilla's junk either.
|
||||
|
|
|
@ -29,7 +29,7 @@ export default class Clippy extends BaseSite {
|
|||
this.inject(Fine);
|
||||
this.inject(Apollo, false);
|
||||
|
||||
this.inject(Switchboard);
|
||||
//this.inject(Switchboard);
|
||||
}
|
||||
|
||||
onLoad() {
|
||||
|
|
|
@ -49,6 +49,7 @@ export default class Chat extends Module {
|
|||
|
||||
this.ChatController.on('mount', this.chatMounted, this);
|
||||
this.ChatController.on('unmount', this.chatMounted, this);
|
||||
this.ChatController.on('update', this.chatUpdated, this);
|
||||
this.ChatController.on('receive-props', this.chatUpdated, this);
|
||||
|
||||
this.ChatController.ready((cls, instances) => {
|
||||
|
@ -167,7 +168,7 @@ export default class Chat extends Module {
|
|||
|
||||
|
||||
chatUpdated(chat, props) {
|
||||
if ( get('data.clip.broadcaster.id', props) !== get('data.clip.broadcaster.id', chat.props) ) {
|
||||
if ( ! chat._ffz_room || props?.data?.clip?.broadcaster?.id !== chat._ffz_room.id ) {
|
||||
this.chatUmounted(chat);
|
||||
this.chatMounted(chat, props);
|
||||
return;
|
||||
|
|
|
@ -82,7 +82,7 @@ export default class CSSTweaks extends Module {
|
|||
const raw = (await import(/* webpackChunkName: "site-css-tweaks" */ './styles.js')).default;
|
||||
for(const key of raw.keys()) {
|
||||
const k = key.slice(2, key.length - (key.endsWith('.scss') ? 5 : 4));
|
||||
this.chunks[k] = raw(key);
|
||||
this.chunks[k] = raw(key).default;
|
||||
}
|
||||
|
||||
this.chunks_loaded = true;
|
||||
|
|
|
@ -163,7 +163,7 @@ export default class ChannelBar extends Module {
|
|||
|
||||
updateMetadata(inst, keys) {
|
||||
const container = this.fine.getChildNode(inst),
|
||||
metabar = container && container.querySelector && container.querySelector('.channel-info-bar__action-container > .tw-flex,.channel-info-bar__content-right > .tw-align-items-start > .tw-flex:last-child');
|
||||
metabar = container?.querySelector?.('.channel-info-bar__action-container > .tw-flex,.channel-info-bar__content-right > .tw-align-items-start > .tw-flex:last-child');
|
||||
|
||||
if ( ! inst._ffz_mounted || ! metabar )
|
||||
return;
|
||||
|
|
|
@ -332,7 +332,7 @@ export default class CSSTweaks extends Module {
|
|||
const raw = (await import(/* webpackChunkName: "site-css-tweaks" */ './styles.js')).default;
|
||||
for(const key of raw.keys()) {
|
||||
const k = key.slice(2, key.length - (key.endsWith('.scss') ? 5 : 4));
|
||||
this.chunks[k] = raw(key);
|
||||
this.chunks[k] = raw(key).default;
|
||||
}
|
||||
|
||||
this.chunks_loaded = true;
|
||||
|
|
|
@ -118,7 +118,11 @@ export default class MenuButton extends SiteModule {
|
|||
if ( ! container )
|
||||
return;
|
||||
|
||||
const user_stuff = container.querySelector(':scope > .tw-justify-content-end:last-child');
|
||||
let user_stuff = null;
|
||||
try {
|
||||
user_stuff = container.querySelector(':scope > .tw-justify-content-end:last-child');
|
||||
} catch(err) { /* dumb browsers with no :scope are dumb */ }
|
||||
|
||||
if ( user_stuff )
|
||||
container = user_stuff;
|
||||
else
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
<figure :class="[(isOpen || ! val || ! val.length) ? 'ffz-i-search' : val]" />
|
||||
</div>
|
||||
<input
|
||||
ref="input"
|
||||
:id="'icon-search$' + id"
|
||||
ref="input"
|
||||
:placeholder="('setting.icon.search', 'Search for Icon')"
|
||||
:value="isOpen ? search : val"
|
||||
:class="[clearable ? 'tw-pd-r-5' : 'tw-pd-r-1']"
|
||||
|
@ -41,7 +41,7 @@
|
|||
<balloon v-if="open" :dir="direction" color="background-base">
|
||||
<div ref="list">
|
||||
<simplebar classes="scrollable-area--suppress-scroll-x ffz--icon-picker__list">
|
||||
<div v-if="visible.length" role="radiogroup" class="tw-pd-1 tw-flex tw-flex-wrap tw-justify-content-between" >
|
||||
<div v-if="visible.length" role="radiogroup" class="tw-pd-1 tw-flex tw-flex-wrap tw-justify-content-between">
|
||||
<div
|
||||
v-for="i of visible"
|
||||
:key="i[0]"
|
||||
|
@ -205,7 +205,7 @@ export default {
|
|||
return this.icons;
|
||||
|
||||
const search = this.search.toLowerCase().replace(' ', '-'),
|
||||
reg = new RegExp('(?:^|-| )' + escape_regex(search), 'i');
|
||||
reg = new RegExp(`(?:^|-| )${escape_regex(search)}`, 'i');
|
||||
|
||||
return this.icons.filter(x => reg.test(x[1]));
|
||||
},
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<template>
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<div v-html="output" />
|
||||
</template>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// ============================================================================
|
||||
|
||||
import Module from 'utilities/module';
|
||||
import {has, once} from 'utilities/object';
|
||||
import {has} from 'utilities/object';
|
||||
|
||||
|
||||
let last_muncher = 0;
|
||||
|
|
|
@ -32,8 +32,8 @@ export function duration_to_string(elapsed, separate_days, days_only, no_hours,
|
|||
|
||||
|
||||
export function print_duration(seconds) {
|
||||
let minutes = Math.floor(seconds / 60),
|
||||
hours = Math.floor(minutes / 60);
|
||||
let minutes = Math.floor(seconds / 60);
|
||||
const hours = Math.floor(minutes / 60);
|
||||
|
||||
minutes %= 60;
|
||||
seconds %= 60;
|
||||
|
|
|
@ -445,7 +445,7 @@ export default class TranslationCore {
|
|||
if ( locale == null )
|
||||
locale = this.locale;
|
||||
|
||||
let val = get(node.v, data);
|
||||
const val = get(node.v, data);
|
||||
if ( val == null )
|
||||
return null;
|
||||
|
||||
|
|
|
@ -173,7 +173,7 @@ export default class TwitchData extends Module {
|
|||
// ========================================================================
|
||||
|
||||
getStreamMeta(id, login) {
|
||||
return new Promise(async (s, f) => {
|
||||
return new Promise((s, f) => {
|
||||
if ( id ) {
|
||||
if ( this._waiting_stream_ids.has(id) )
|
||||
this._waiting_stream_ids.get(id).push([s, f]);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue