1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-06-28 15:27:43 +00:00
The Great Maintenance Update. No new features here. Instead, we've updated the build system to webpack 4, updated all our dependencies, and cleaned up a lot of linting issues.
This commit is contained in:
SirStendec 2019-06-20 15:15:54 -04:00
parent 014eb203c3
commit 33e81bc7eb
60 changed files with 238 additions and 209 deletions

View file

@ -138,7 +138,6 @@ module.exports = {
"react/jsx-no-bind": "error", "react/jsx-no-bind": "error",
"react/jsx-no-comment-textnodes": "error", "react/jsx-no-comment-textnodes": "error",
"react/jsx-no-duplicate-props": "error", "react/jsx-no-duplicate-props": "error",
"react/jsx-no-literals": ["warn"],
"react/jsx-no-target-blank": "error", "react/jsx-no-target-blank": "error",
"react/jsx-sort-props": ["error", { "react/jsx-sort-props": ["error", {
"callbacksLast": true, "callbacksLast": true,

View file

@ -14,6 +14,7 @@
"build:all": "npm run build && npm run build:clips", "build:all": "npm run build && npm run build:clips",
"build": "npm run build:prod", "build": "npm run build:prod",
"build:clips": "cross-env NODE_ENV=production webpack --config webpack.clips.prod.js", "build:clips": "cross-env NODE_ENV=production webpack --config webpack.clips.prod.js",
"build:clips:dev": "npm run clean && webpack --config webpack.clips.dev.js",
"build:stats": "cross-env NODE_ENV=production webpack --config webpack.web.prod.js --json > stats.json", "build:stats": "cross-env NODE_ENV=production webpack --config webpack.web.prod.js --json > stats.json",
"build:prod": "cross-env NODE_ENV=production webpack --config webpack.web.prod.js", "build:prod": "cross-env NODE_ENV=production webpack --config webpack.web.prod.js",
"build:dev": "npm run clean && webpack --config webpack.web.dev.js" "build:dev": "npm run clean && webpack --config webpack.web.dev.js"
@ -70,7 +71,7 @@
"raven-js": "^3.24.2", "raven-js": "^3.24.2",
"react": "^16.4.1", "react": "^16.4.1",
"safe-regex": "^2.0.2", "safe-regex": "^2.0.2",
"sortablejs": "^1.10.0-rc2", "sortablejs": "^1.10.0-rc1",
"vue": "^2.6.10", "vue": "^2.6.10",
"vue-clickaway": "^2.2.2", "vue-clickaway": "^2.2.2",
"vue-color": "^2.4.6", "vue-color": "^2.4.6",

View file

@ -10,9 +10,7 @@ import { createElement } from 'utilities/dom';
import { timeout, has } from 'utilities/object'; import { timeout, has } from 'utilities/object';
import { getBuster } from 'utilities/time'; import { getBuster } from 'utilities/time';
const fetchJSON = (url, options) => { const fetchJSON = (url, options) => fetch(url, options).then(r => r.ok ? r.json() : null).catch(() => null);
return fetch(url, options).then(r => r.ok ? r.json() : null).catch(() => null);
}
// ============================================================================ // ============================================================================
// AddonManager // AddonManager

View file

@ -14,8 +14,7 @@ import NewTransCore from 'utilities/translation-core';
const FACES = ['(・`ω´・)', ';;w;;', 'owo', 'ono', 'oAo', 'oxo', 'ovo;', 'UwU', '>w<', '^w^', '> w >', 'v.v'], const FACES = ['(・`ω´・)', ';;w;;', 'owo', 'ono', 'oAo', 'oxo', 'ovo;', 'UwU', '>w<', '^w^', '> w >', 'v.v'],
transformText = (ast, fn) => { transformText = (ast, fn) => ast.map(node => {
return ast.map(node => {
if ( typeof node === 'string' ) if ( typeof node === 'string' )
return fn(node); return fn(node);
@ -26,8 +25,7 @@ const FACES = ['(・`ω´・)', ';;w;;', 'owo', 'ono', 'oAo', 'oxo', 'ovo;', 'Uw
} }
return node; return node;
}) }),
},
owo = text => text owo = text => text
.replace(/(?:r|l)/g, 'w') .replace(/(?:r|l)/g, 'w')

View file

@ -115,11 +115,9 @@ class FrankerFaceZ extends Module {
out.unshift(['initialization', logs.join('\n')]); out.unshift(['initialization', logs.join('\n')]);
} }
return out.map(x => { return out.map(x => `${x[0]}
return `${x[0]}
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
${typeof x[1] === 'string' ? x[1] : JSON.stringify(x[1], null, 4)}` ${typeof x[1] === 'string' ? x[1] : JSON.stringify(x[1], null, 4)}`).join('\n\n');
}).join('\n\n');
} }

View file

@ -255,8 +255,8 @@ export default class Actions extends Module {
reason_elements.push(<li class="tw-full-width tw-relative"> reason_elements.push(<li class="tw-full-width tw-relative">
<a <a
href="#" href="#"
onClick={click_fn(text)}
class="tw-block tw-full-width tw-interactable tw-interactable--inverted tw-interactive tw-pd-05" class="tw-block tw-full-width tw-interactable tw-interactable--inverted tw-interactive tw-pd-05"
onClick={click_fn(text)}
> >
{text} {text}
</a> </a>
@ -272,8 +272,8 @@ export default class Actions extends Module {
reason_elements.push(<li class="tw-full-width tw-relative"> reason_elements.push(<li class="tw-full-width tw-relative">
<a <a
href="#" href="#"
onClick={click_fn(rule)}
class="tw-block tw-full-width tw-interactable tw-interactable--inverted tw-interactive tw-pd-05" class="tw-block tw-full-width tw-interactable tw-interactable--inverted tw-interactive tw-pd-05"
onClick={click_fn(rule)}
> >
{rule} {rule}
</a> </a>

View file

@ -1188,6 +1188,8 @@ export default class Chat extends Module {
idx += split_chars(ret).length; idx += split_chars(ret).length;
out.push(ret); out.push(ret);
} }
first = false;
} }
if ( ! emotes_only ) if ( ! emotes_only )

View file

@ -1006,8 +1006,9 @@ export const AddonEmotes = {
modifiers = ds.modifierInfo; modifiers = ds.modifierInfo;
let name, preview, source, owner, mods, fav_source, emote_id, let name, preview, source, owner, mods, fav_source, emote_id,
plain_name = false, plain_name = false;
hide_source = ds.noSource === 'true';
const hide_source = ds.noSource === 'true';
if ( modifiers && modifiers !== 'null' ) { if ( modifiers && modifiers !== 'null' ) {
mods = JSON.parse(modifiers).map(([set_id, emote_id]) => { mods = JSON.parse(modifiers).map(([set_id, emote_id]) => {

View file

@ -27,6 +27,8 @@ export default class Logviewer extends Module {
const token = this._token; const token = this._token;
if ( token && token.token && token.expires > ((Date.now() / 1000) + 300) ) if ( token && token.token && token.expires > ((Date.now() / 1000) + 300) )
return token.token; return token.token;
return null;
} }

View file

@ -7,7 +7,9 @@
<div class="tw-flex-grow-1"> <div class="tw-flex-grow-1">
<template v-if="! editing"> <template v-if="! editing">
<h4>{{ title }}</h4> <h4>{{ title }}</h4>
<div class="description">{{ description }}</div> <div class="description">
{{ description }}
</div>
<div v-if="canEdit" class="visibility tw-c-text-alt"> <div v-if="canEdit" class="visibility tw-c-text-alt">
{{ t('setting.actions.visible', 'visible: {list}', {list: visibility}) }} {{ t('setting.actions.visible', 'visible: {list}', {list: visibility}) }}
</div> </div>
@ -63,8 +65,8 @@
</div> </div>
<component <component
v-if="renderer"
:is="renderer.editor" :is="renderer.editor"
v-if="renderer"
v-model="edit_data.appearance" v-model="edit_data.appearance"
/> />
</section> </section>
@ -82,9 +84,15 @@
v-model="edit_data.display.mod" v-model="edit_data.display.mod"
class="tw-border-radius-medium tw-font-size-6 tw-full-width tw-select tw-pd-l-1 tw-pd-r-3 tw-pd-y-05 tw-mg-y-05" class="tw-border-radius-medium tw-font-size-6 tw-full-width tw-select tw-pd-l-1 tw-pd-r-3 tw-pd-y-05 tw-mg-y-05"
> >
<option :value="undefined" selected>{{ t('setting.unset', 'Unset') }}</option> <option :value="undefined" selected>
<option :value="true">{{ t('setting.true', 'True') }}</option> {{ t('setting.unset', 'Unset') }}
<option :value="false">{{ t('setting.false', 'False') }}</option> </option>
<option :value="true">
{{ t('setting.true', 'True') }}
</option>
<option :value="false">
{{ t('setting.false', 'False') }}
</option>
</select> </select>
</div> </div>
@ -98,9 +106,15 @@
v-model="edit_data.display.mod_icons" v-model="edit_data.display.mod_icons"
class="tw-border-radius-medium tw-font-size-6 tw-full-width tw-select tw-pd-l-1 tw-pd-r-3 tw-pd-y-05 tw-mg-y-05" class="tw-border-radius-medium tw-font-size-6 tw-full-width tw-select tw-pd-l-1 tw-pd-r-3 tw-pd-y-05 tw-mg-y-05"
> >
<option :value="undefined" selected>{{ t('setting.unset', 'Unset') }}</option> <option :value="undefined" selected>
<option :value="true">{{ t('setting.visible', 'Visible') }}</option> {{ t('setting.unset', 'Unset') }}
<option :value="false">{{ t('setting.hidden', 'Hidden') }}</option> </option>
<option :value="true">
{{ t('setting.visible', 'Visible') }}
</option>
<option :value="false">
{{ t('setting.hidden', 'Hidden') }}
</option>
</select> </select>
</div> </div>
@ -114,9 +128,15 @@
v-model="edit_data.display.deleted" v-model="edit_data.display.deleted"
class="tw-border-radius-medium tw-font-size-6 tw-full-width tw-select tw-pd-l-1 tw-pd-r-3 tw-pd-y-05 tw-mg-y-05" class="tw-border-radius-medium tw-font-size-6 tw-full-width tw-select tw-pd-l-1 tw-pd-r-3 tw-pd-y-05 tw-mg-y-05"
> >
<option :value="undefined" selected>{{ t('setting.unset', 'Unset') }}</option> <option :value="undefined" selected>
<option :value="true">{{ t('setting.true', 'True') }}</option> {{ t('setting.unset', 'Unset') }}
<option :value="false">{{ t('setting.false', 'False') }}</option> </option>
<option :value="true">
{{ t('setting.true', 'True') }}
</option>
<option :value="false">
{{ t('setting.false', 'False') }}
</option>
</select> </select>
</div> </div>
@ -129,8 +149,8 @@
<div class="ffz--inline tw-flex"> <div class="ffz--inline tw-flex">
<div class="tw-pd-r-1 tw-checkbox"> <div class="tw-pd-r-1 tw-checkbox">
<input <input
ref="key_ctrl"
:id="'key_ctrl$' + id" :id="'key_ctrl$' + id"
ref="key_ctrl"
:checked="edit_data.display.keys & 1" :checked="edit_data.display.keys & 1"
type="checkbox" type="checkbox"
class="tw-checkbox__input" class="tw-checkbox__input"
@ -143,8 +163,8 @@
<div class="tw-pd-r-1 tw-checkbox"> <div class="tw-pd-r-1 tw-checkbox">
<input <input
ref="key_shift"
:id="'key_shift$' + id" :id="'key_shift$' + id"
ref="key_shift"
:checked="edit_data.display.keys & 2" :checked="edit_data.display.keys & 2"
type="checkbox" type="checkbox"
class="tw-checkbox__input" class="tw-checkbox__input"
@ -157,8 +177,8 @@
<div class="tw-pd-r-1 tw-checkbox"> <div class="tw-pd-r-1 tw-checkbox">
<input <input
ref="key_alt"
:id="'key_alt$' + id" :id="'key_alt$' + id"
ref="key_alt"
:checked="edit_data.display.keys & 4" :checked="edit_data.display.keys & 4"
type="checkbox" type="checkbox"
class="tw-checkbox__input" class="tw-checkbox__input"
@ -171,8 +191,8 @@
<div class="tw-pd-r-1 tw-checkbox"> <div class="tw-pd-r-1 tw-checkbox">
<input <input
ref="key_meta"
:id="'key_meta$' + id" :id="'key_meta$' + id"
ref="key_meta"
:checked="edit_data.display.keys & 8" :checked="edit_data.display.keys & 8"
type="checkbox" type="checkbox"
class="tw-checkbox__input" class="tw-checkbox__input"
@ -183,10 +203,6 @@
</label> </label>
</div> </div>
</div> </div>
<div class="tw-pd-t-05">
Note: This currently requires Chat > Behavior > Freeze Chat Scrolling to be enabled.
</div>
</div> </div>
</div> </div>
</section> </section>
@ -215,14 +231,13 @@
</div> </div>
<component <component
v-if="action_def && action_def.editor"
:is="action_def.editor" :is="action_def.editor"
v-if="action_def && action_def.editor"
:value="edit_data.options" :value="edit_data.options"
:defaults="action_def.defaults" :defaults="action_def.defaults"
:vars="vars" :vars="vars"
@input="onChangeAction($event)" @input="onChangeAction($event)"
/> />
</section> </section>
</template> </template>
</div> </div>
@ -406,7 +421,7 @@ export default {
const def = this.display && this.data.actions[this.display.action]; const def = this.display && this.data.actions[this.display.action];
if ( ! def || ! def.description ) if ( ! def || ! def.description )
return; return null;
const data = this.getData(), const data = this.getData(),
out = maybe_call(def.description, this, data, def), out = maybe_call(def.description, this, data, def),
@ -414,6 +429,8 @@ export default {
if ( out ) if ( out )
return this.t(i18n, out, data); return this.t(i18n, out, data);
return null;
}, },
visibility() { visibility() {

View file

@ -8,8 +8,8 @@
class="ffz-mod-icon mod-icon tw-c-text-alt-2 tw-font-size-4" class="ffz-mod-icon mod-icon tw-c-text-alt-2 tw-font-size-4"
> >
<component <component
v-if="renderer && renderer.component"
:is="renderer.component" :is="renderer.component"
v-if="renderer && renderer.component"
:data="act.appearance" :data="act.appearance"
:color="color" :color="color"
/> />

View file

@ -23,10 +23,9 @@
</div> </div>
<div v-else> <div v-else>
<addon <addon
v-for="addon in sorted_addons" v-for="addon in visible_addons"
v-if="shouldShow(addon)"
:key="addon.id"
:id="addon.id" :id="addon.id"
:key="addon.id"
:addon="addon" :addon="addon"
:item="item" :item="item"
@navigate="navigate" @navigate="navigate"
@ -97,6 +96,10 @@ export default {
}, },
computed: { computed: {
visible_addons() {
return this.sorted_addons.filter(addon => this.shouldShow(addon));
},
sorted_addons() { sorted_addons() {
const addons = this.item.getAddons(); const addons = this.item.getAddons();

View file

@ -13,8 +13,7 @@
</div> </div>
<ul v-else class="ffz--term-list tw-mg-t-05"> <ul v-else class="ffz--term-list tw-mg-t-05">
<badge-term-editor <badge-term-editor
v-for="term in val" v-for="term in terms"
v-if="term.t !== 'inherit'"
:key="term.id" :key="term.id"
:term="term.v" :term="term.v"
:badges="data" :badges="data"
@ -53,6 +52,19 @@ export default {
for(const val of this.val) for(const val of this.val)
if ( val.t === 'inherit' ) if ( val.t === 'inherit' )
return true; return true;
return false;
},
terms() {
const out = [];
if ( Array.isArray(this.val) )
for(const term of this.val)
if ( term && term.t !== 'inherit' )
out.push(term);
return out;
}, },
val() { val() {

View file

@ -18,7 +18,8 @@
<select <select
v-if="editing" v-if="editing"
v-model="edit_data.v" v-model="edit_data.v"
class="tw-block tw-full-width tw-border-radius-medium tw-font-size-6 tw-full-width tw-select tw-pd-x-1 tw-pd-y-05 tw-mg-y-05"> class="tw-block tw-full-width tw-border-radius-medium tw-font-size-6 tw-full-width tw-select tw-pd-x-1 tw-pd-y-05 tw-mg-y-05"
>
<optgroup <optgroup
v-for="section in badges" v-for="section in badges"
:key="section.title" :key="section.title"
@ -180,6 +181,8 @@ export default {
if ( badge.id === v ) if ( badge.id === v )
return badge; return badge;
} }
return null;
} }
}, },

View file

@ -38,8 +38,8 @@
class="ffz--badge-info tw-pd-y-1 tw-pd-r-1 tw-flex tw-checkbox" class="ffz--badge-info tw-pd-y-1 tw-pd-r-1 tw-flex tw-checkbox"
> >
<input <input
:checked="badgeChecked(i.id)"
:id="i.id" :id="i.id"
:checked="badgeChecked(i.id)"
type="checkbox" type="checkbox"
class="tw-checkbox__input" class="tw-checkbox__input"
@click="onChange(i.id, $event)" @click="onChange(i.id, $event)"

View file

@ -13,8 +13,7 @@
</div> </div>
<ul v-else class="ffz--term-list tw-mg-t-05"> <ul v-else class="ffz--term-list tw-mg-t-05">
<term-editor <term-editor
v-for="term in val" v-for="term in terms"
v-if="term.t !== 'inherit'"
:key="term.id" :key="term.id"
:term="term.v" :term="term.v"
:colored="item.colored" :colored="item.colored"
@ -54,6 +53,19 @@ export default {
for(const val of this.val) for(const val of this.val)
if ( val.t === 'inherit' ) if ( val.t === 'inherit' )
return true; return true;
return false;
},
terms() {
const out = [];
if ( Array.isArray(this.val) )
for(const term of this.val)
if ( term && term.t !== 'inherit' )
out.push(term);
return out;
}, },
val() { val() {

View file

@ -232,6 +232,8 @@ export default {
for(const val of this.val) for(const val of this.val)
if ( val.t === 'inherit' ) if ( val.t === 'inherit' )
return true; return true;
return false;
}, },
sample_user() { sample_user() {

View file

@ -39,8 +39,7 @@
</div> </div>
<ul v-else class="ffz--term-list tw-mg-t-05"> <ul v-else class="ffz--term-list tw-mg-t-05">
<reason-editor <reason-editor
v-for="reason in val" v-for="reason in reasons"
v-if="reason.t !== 'inherit'"
:key="reason.id" :key="reason.id"
:reason="reason.v" :reason="reason.v"
@remove="remove(reason)" @remove="remove(reason)"
@ -74,10 +73,22 @@ export default {
return ! this.val.length || this.val.length === 1 && this.hasInheritance; return ! this.val.length || this.val.length === 1 && this.hasInheritance;
}, },
reasons() {
const out = [];
if ( Array.isArray(this.val) )
for(const reason of this.val)
if ( reason.t !== 'inherit' )
out.push(reason);
return out;
},
hasInheritance() { hasInheritance() {
for(const val of this.val) for(const val of this.val)
if ( val.t === 'inherit' ) if ( val.t === 'inherit' )
return true; return true;
return false;
}, },
val() { val() {

View file

@ -4,8 +4,8 @@
<input <input
v-if="showInput" v-if="showInput"
ref="input" ref="input"
v-bind="$attrs"
v-model="color" v-model="color"
v-bind="$attrs"
type="text" type="text"
class="tw-block tw-border-radius-medium tw-font-size-6 tw-full-width tw-input tw-pd-l-1 tw-pd-r-3 tw-pd-y-05 tw-mg-y-05" class="tw-block tw-border-radius-medium tw-font-size-6 tw-full-width tw-input tw-pd-l-1 tw-pd-r-3 tw-pd-y-05 tw-mg-y-05"
autocapitalize="off" autocapitalize="off"
@ -22,7 +22,7 @@
<figure v-else-if="color" :style="`background-color: ${color}`" /> <figure v-else-if="color" :style="`background-color: ${color}`" />
<figure v-else class="ffz-i-eyedropper" /> <figure v-else class="ffz-i-eyedropper" />
</button> </button>
<div v-on-clickaway="closePicker" v-if="open" class="tw-absolute tw-z-default tw-right-0"> <div v-if="open" v-on-clickaway="closePicker" class="tw-absolute tw-z-default tw-right-0">
<chrome-picker :value="colors" @input="onPick" /> <chrome-picker :value="colors" @input="onPick" />
</div> </div>
</div> </div>
@ -39,8 +39,8 @@
<figure v-else class="ffz-i-eyedropper" /> <figure v-else class="ffz-i-eyedropper" />
</button> </button>
<div <div
v-on-clickaway="closePicker"
v-if="open" v-if="open"
v-on-clickaway="closePicker"
:class="{'ffz-bottom-100': openUp}" :class="{'ffz-bottom-100': openUp}"
class="tw-absolute tw-z-default tw-balloon--up tw-balloon--right" class="tw-absolute tw-z-default tw-balloon--up tw-balloon--right"
> >

View file

@ -13,8 +13,12 @@
class="tw-border-radius-medium tw-font-size-6 tw-select tw-pd-l-1 tw-pd-r-3 tw-pd-y-05 tw-mg-x-05" class="tw-border-radius-medium tw-font-size-6 tw-select tw-pd-l-1 tw-pd-r-3 tw-pd-y-05 tw-mg-x-05"
@change="onSort" @change="onSort"
> >
<option :selected="sort_by === 0">{{ t('setting.experiments.sort-name', 'Sort By: Name') }}</option> <option :selected="sort_by === 0">
<option :selected="sort_by === 1">{{ t('setting.experiments.sort-rarity', 'Sort By: Rarity') }}</option> {{ t('setting.experiments.sort-name', 'Sort By: Name') }}
</option>
<option :selected="sort_by === 1">
{{ t('setting.experiments.sort-rarity', 'Sort By: Rarity') }}
</option>
</select> </select>
</div> </div>
@ -29,7 +33,6 @@
:data-key="key" :data-key="key"
> >
<div class="tw-elevation-1 tw-c-background-base tw-border tw-pd-y-05 tw-pd-x-1 tw-mg-y-05 tw-flex tw-flex-nowrap"> <div class="tw-elevation-1 tw-c-background-base tw-border tw-pd-y-05 tw-pd-x-1 tw-mg-y-05 tw-flex tw-flex-nowrap">
<div class="tw-flex-grow-1"> <div class="tw-flex-grow-1">
<h4>{{ exp.name }}</h4> <h4>{{ exp.name }}</h4>
<div v-if="exp.description" class="description"> <div v-if="exp.description" class="description">

View file

@ -6,10 +6,10 @@
<component <component
:is="component" :is="component"
v-model="editing"
:type="type" :type="type"
:filters="filters" :filters="filters"
:context="context" :context="context"
v-model="editing"
/> />
<div <div

View file

@ -2,7 +2,9 @@
<div class="ffz--home tw-flex tw-flex-nowrap"> <div class="ffz--home tw-flex tw-flex-nowrap">
<div class="tw-flex-grow-1"> <div class="tw-flex-grow-1">
<div class="tw-align-center"> <div class="tw-align-center">
<h1 class="ffz-i-zreknarf ffz-i-pd-1">FrankerFaceZ</h1> <h1 class="ffz-i-zreknarf ffz-i-pd-1">
FrankerFaceZ
</h1>
<span class="tw-c-text-alt"> <span class="tw-c-text-alt">
{{ t('home.tag-line', 'The Twitch Enhancement Suite') }} {{ t('home.tag-line', 'The Twitch Enhancement Suite') }}
</span> </span>
@ -11,8 +13,6 @@
<section class="tw-pd-t-1 tw-border-t tw-mg-t-1"> <section class="tw-pd-t-1 tw-border-t tw-mg-t-1">
<markdown :source="t('home.about', md)" /> <markdown :source="t('home.about', md)" />
</section> </section>
</div> </div>
<div class="tw-mg-l-1 tw-flex-shrink-0 tweet-column"> <div class="tw-mg-l-1 tw-flex-shrink-0 tweet-column">
<div class="tw-flex tw-mg-b-1"> <div class="tw-flex tw-mg-b-1">

View file

@ -4,7 +4,9 @@
class="ffz-dialog ffz-main-menu tw-elevation-3 tw-c-background-alt tw-c-text-base tw-border tw-flex tw-flex-nowrap tw-flex-column" class="ffz-dialog ffz-main-menu tw-elevation-3 tw-c-background-alt tw-c-text-base tw-border tw-flex tw-flex-nowrap tw-flex-column"
> >
<header ref="header" class="tw-c-background-base tw-full-width tw-align-items-center tw-flex tw-flex-nowrap" @dblclick="maybeResize($event)"> <header ref="header" class="tw-c-background-base tw-full-width tw-align-items-center tw-flex tw-flex-nowrap" @dblclick="maybeResize($event)">
<h3 class="ffz-i-zreknarf ffz-i-pd-1">FrankerFaceZ</h3> <h3 class="ffz-i-zreknarf ffz-i-pd-1">
FrankerFaceZ
</h3>
<div class="tw-flex-grow-1 tw-pd-x-2"> <div class="tw-flex-grow-1 tw-pd-x-2">
<div class="tw-search-input"> <div class="tw-search-input">
<label for="ffz-main-menu.search" class="tw-hide-accessible">{{ t('main-menu.search', 'Search Settings') }}</label> <label for="ffz-main-menu.search" class="tw-hide-accessible">{{ t('main-menu.search', 'Search Settings') }}</label>

View file

@ -6,8 +6,9 @@
<section <section
v-if="item.description" v-if="item.description"
class="tw-pd-b-1" class="tw-pd-b-1"
v-html="t(item.desc_i18n_key, item.description, item)" >
/> <markdown :source="t(item.desc_i18n_key, item.description, item)" />
</section>
<div <div
v-for="i in item.contents" v-for="i in item.contents"
:key="i.full_key" :key="i.full_key"

View file

@ -57,8 +57,8 @@
:class="{'ffz-unmatched-item': ! shouldShow(i)}" :class="{'ffz-unmatched-item': ! shouldShow(i)}"
> >
<component <component
ref="children"
:is="i.component" :is="i.component"
ref="children"
:context="context" :context="context"
:item="i" :item="i"
:filter="filter" :filter="filter"

View file

@ -11,8 +11,7 @@
@keyup.*="expandAll" @keyup.*="expandAll"
> >
<li <li
v-for="item in modal" v-for="item in displayed"
v-if="shouldShow(item)"
:key="item.full_key" :key="item.full_key"
:class="[currentItem === item ? 'active' : '']" :class="[currentItem === item ? 'active' : '']"
role="presentation" role="presentation"
@ -99,6 +98,10 @@ export default {
computed: { computed: {
tabIndex() { tabIndex() {
return this.root ? undefined : 0; return this.root ? undefined : 0;
},
displayed() {
return this.modal.filter(item => this.shouldShow(item));
} }
}, },

View file

@ -127,9 +127,9 @@
</section> </section>
<filter-editor <filter-editor
v-model="rules"
:filters="filters" :filters="filters"
:context="test_context" :context="test_context"
v-model="rules"
/> />
</div> </div>
</div> </div>

View file

@ -16,8 +16,8 @@
{{ t(context.currentProfile.i18n_key, context.currentProfile.title, context.currentProfile) }} {{ t(context.currentProfile.i18n_key, context.currentProfile.title, context.currentProfile) }}
</div> </div>
<div <div
v-on-clickaway="hide"
v-if="opened" v-if="opened"
v-on-clickaway="hide"
class="tw-balloon tw-block tw-balloon--lg tw-balloon--down tw-balloon--left" class="tw-balloon tw-block tw-balloon--lg tw-balloon--down tw-balloon--left"
> >
<div <div

View file

@ -5,8 +5,8 @@
> >
<div class="tw-flex tw-align-items-center tw-checkbox"> <div class="tw-flex tw-align-items-center tw-checkbox">
<input <input
ref="control"
:id="item.full_key" :id="item.full_key"
ref="control"
:checked="value" :checked="value"
type="checkbox" type="checkbox"
class="tw-checkbox__input" class="tw-checkbox__input"

View file

@ -10,8 +10,8 @@
</label> </label>
<color-picker <color-picker
ref="control"
:id="item.full_key" :id="item.full_key"
ref="control"
:nullable="true" :nullable="true"
:value="color" :value="color"
@input="onInput" @input="onInput"

View file

@ -11,8 +11,8 @@
<div class="tw-flex tw-flex-column tw-mg-05"> <div class="tw-flex tw-flex-column tw-mg-05">
<select <select
ref="control"
:id="item.full_key" :id="item.full_key"
ref="control"
class="tw-border-radius-medium tw-font-size-6 tw-select tw-pd-l-1 tw-pd-r-3 tw-pd-y-05" class="tw-border-radius-medium tw-font-size-6 tw-select tw-pd-l-1 tw-pd-r-3 tw-pd-y-05"
@change="onChange" @change="onChange"
> >

View file

@ -1,9 +1,8 @@
<template lang="html"> <template lang="html">
<div class="ffz--widget ffz--hotkey-input"> <div class="ffz--widget ffz--hotkey-input">
<label <label :for="item.full_key">
:for="item.full_key" {{ t(item.i18n_key, item.title, item) }}
v-html="t(item.i18n_key, item.title, item)" </label>
/>
<div class="tw-relative"> <div class="tw-relative">
<div class="tw-input__icon-group tw-input__icon-group--right"> <div class="tw-input__icon-group tw-input__icon-group--right">
<div class="tw-input__icon"> <div class="tw-input__icon">
@ -11,8 +10,8 @@
</div> </div>
</div> </div>
<div <div
ref="display"
:id="item.full_key" :id="item.full_key"
ref="display"
type="text" type="text"
class="tw-mg-05 tw-input tw-input--icon-right" class="tw-mg-05 tw-input tw-input--icon-right"
tabindex="0" tabindex="0"

View file

@ -12,8 +12,8 @@
</section> </section>
<div v-for="(i, idx) in data" :key="idx" class="tw-mg-l-1"> <div v-for="(i, idx) in data" :key="idx" class="tw-mg-l-1">
<input <input
:name="item.full_key"
:id="item.full_key + idx" :id="item.full_key + idx"
:name="item.full_key"
:value="i.value" :value="i.value"
type="radio" type="radio"
class="tw-radio__input" class="tw-radio__input"

View file

@ -10,8 +10,8 @@
</label> </label>
<select <select
ref="control"
:id="item.full_key" :id="item.full_key"
ref="control"
class="tw-border-radius-medium tw-font-size-6 tw-select tw-pd-l-1 tw-pd-r-3 tw-pd-y-05 tw-mg-05" class="tw-border-radius-medium tw-font-size-6 tw-select tw-pd-l-1 tw-pd-r-3 tw-pd-y-05 tw-mg-05"
@change="onChange" @change="onChange"
> >

View file

@ -10,8 +10,8 @@
</label> </label>
<input <input
ref="control"
:id="item.full_key" :id="item.full_key"
ref="control"
:value="value" :value="value"
class="tw-border-radius-medium tw-font-size-6 tw-pd-x-1 tw-pd-y-05 tw-mg-05 tw-input" class="tw-border-radius-medium tw-font-size-6 tw-pd-x-1 tw-pd-y-05 tw-mg-05 tw-input"
@change="onChange" @change="onChange"

View file

@ -42,10 +42,18 @@
v-model="edit_data.t" v-model="edit_data.t"
class="tw-block tw-border-radius-medium tw-font-size-6 tw-select tw-pd-l-1 tw-pd-r-3 tw-pd-y-05 ffz-min-width-unset" class="tw-block tw-border-radius-medium tw-font-size-6 tw-select tw-pd-l-1 tw-pd-r-3 tw-pd-y-05 ffz-min-width-unset"
> >
<option value="text">{{ t('setting.terms.type.text', 'Text') }}</option> <option value="text">
<option value="glob">{{ t('setting.terms.type.glob', 'Glob') }}</option> {{ t('setting.terms.type.text', 'Text') }}
<option v-if="words" value="regex">{{ t('setting.terms.type.regex-word', 'Regex (Word)') }}</option> </option>
<option value="raw">{{ t('setting.terms.type.regex', 'Regex') }}</option> <option value="glob">
{{ t('setting.terms.type.glob', 'Glob') }}
</option>
<option v-if="words" value="regex">
{{ t('setting.terms.type.regex-word', 'Regex (Word)') }}
</option>
<option value="raw">
{{ t('setting.terms.type.regex', 'Regex') }}
</option>
</select> </select>
</div> </div>
<div v-if="removable" class="tw-flex-shrink-0 tw-mg-r-05 tw-tooltip-wrapper"> <div v-if="removable" class="tw-flex-shrink-0 tw-mg-r-05 tw-tooltip-wrapper">

View file

@ -172,7 +172,7 @@ export default class Metadata extends Module {
return `${delayed}${data.delay.toFixed(2)}s`; return `${delayed}${data.delay.toFixed(2)}s`;
}, },
click(data) { click() {
const Player = this.resolve('site.player'), const Player = this.resolve('site.player'),
internal = Player.getInternalPlayer(); internal = Player.getInternalPlayer();

View file

@ -60,8 +60,8 @@ export default class TooltipProvider extends Module {
} }
onEnable() { onEnable() {
const container = document.querySelector('#root>div') || document.querySelector('#root') || document.querySelector('.clips-root') || document.body, const container = document.querySelector('#root>div') || document.querySelector('#root') || document.querySelector('.clips-root') || document.body;
is_minimal = false; //container && container.classList.contains('twilight-minimal-root'); // is_minimal = false; //container && container.classList.contains('twilight-minimal-root');
this.tips = new Tooltip(container, 'ffz-tooltip', { this.tips = new Tooltip(container, 'ffz-tooltip', {
html: true, html: true,

View file

@ -124,7 +124,7 @@ export default {
}, },
methods: { methods: {
displayAction(action) { displayAction(action) { // eslint-disable-line no-unused-vars
return true; return true;
}, },

View file

@ -41,7 +41,9 @@
</aspect> </aspect>
</div> </div>
<div class="tw-card-body tw-overflow-hidden tw-relative"> <div class="tw-card-body tw-overflow-hidden tw-relative">
<p class="tw-pd-x-1">{{ slot.item.displayName }}</p> <p class="tw-pd-x-1">
{{ slot.item.displayName }}
</p>
</div> </div>
</div> </div>
</div> </div>

View file

@ -5,10 +5,10 @@
</header> </header>
<filter-editor <filter-editor
v-model="value.data"
:filters="filters" :filters="filters"
:context="context" :context="context"
:max-rules="type.maxRules" :max-rules="type.maxRules"
v-model="value.data"
/> />
</section> </section>
</template> </template>

View file

@ -11,7 +11,7 @@
class="tw-flex-grow-1 tw-mg-l-1 tw-border-radius-medium tw-font-size-6 tw-pd-x-1 tw-pd-y-05 tw-select" class="tw-flex-grow-1 tw-mg-l-1 tw-border-radius-medium tw-font-size-6 tw-pd-x-1 tw-pd-y-05 tw-select"
> >
<option <option
v-for="(route, key) in routes" v-for="(_, key) in routes"
v-once v-once
:key="key" :key="key"
:value="key" :value="key"
@ -88,8 +88,7 @@ export default {
try { try {
return decodeURI(new URL(this.route.url(parts), location)); return decodeURI(new URL(this.route.url(parts), location));
} catch(err) { } catch(err) {
console.error(err); return '(unable to render url)';
return null;
} }
}, },

View file

@ -5,7 +5,7 @@
// ============================================================================ // ============================================================================
import {EventEmitter} from 'utilities/events'; import {EventEmitter} from 'utilities/events';
import {has, get as getter, array_equals, set_equals, map_equals, deep_copy} from 'utilities/object'; import {has, get as getter, array_equals, set_equals, map_equals} from 'utilities/object';
import * as DEFINITIONS from './types'; import * as DEFINITIONS from './types';

View file

@ -8,9 +8,7 @@ import {EventEmitter} from 'utilities/events';
import {has} from 'utilities/object'; import {has} from 'utilities/object';
import {createTester} from 'utilities/filtering'; import {createTester} from 'utilities/filtering';
const fetchJSON = (url, options) => { const fetchJSON = (url, options) => fetch(url, options).then(r => r.ok ? r.json() : null).catch(() => null);
return fetch(url, options).then(r => r.ok ? r.json() : null).catch(() => null);
}
/** /**
* Instances of SettingsProfile are used for getting and setting raw settings * Instances of SettingsProfile are used for getting and setting raw settings
@ -88,7 +86,7 @@ export default class SettingsProfile extends EventEmitter {
if ( ! this.url ) if ( ! this.url )
return false; return false;
const data = fetchJSON(this.url); const data = await fetchJSON(this.url);
if ( ! data || ! data.type === 'profile' || ! data.profile || ! data.values ) if ( ! data || ! data.type === 'profile' || ! data.profile || ! data.values )
return false; return false;

View file

@ -14,7 +14,7 @@ import {createElement} from 'utilities/dom';
import MAIN_URL from 'site/styles/main.scss'; import MAIN_URL from 'site/styles/main.scss';
import Switchboard from './switchboard'; //import Switchboard from './switchboard';
// ============================================================================ // ============================================================================

View file

@ -41,7 +41,7 @@ export default class Line extends Module {
this.chat.context.on('changed:tooltip.link-images', this.maybeUpdateLines, this); this.chat.context.on('changed:tooltip.link-images', this.maybeUpdateLines, this);
this.chat.context.on('changed:tooltip.link-nsfw-images', this.maybeUpdateLines, this); this.chat.context.on('changed:tooltip.link-nsfw-images', this.maybeUpdateLines, this);
this.ChatLine.ready((cls, instances) => { this.ChatLine.ready(cls => {
const t = this, const t = this,
old_render = cls.prototype.render; old_render = cls.prototype.render;

View file

@ -29,10 +29,6 @@ export default class CSSTweaks extends Module {
this.chunks_loaded = false; this.chunks_loaded = false;
} }
onEnable() {
}
toggleHide(key, val) { toggleHide(key, val) {
const k = `hide--${key}`; const k = `hide--${key}`;

View file

@ -38,7 +38,7 @@ export default class ThemeEngine extends Module {
this.settings.add('theme.can-dark', { this.settings.add('theme.can-dark', {
requires: ['context.route.name'], requires: ['context.route.name'],
process(ctx) { process() {
return true; return true;
} }
}); });

View file

@ -59,15 +59,7 @@ export default class ChannelBar extends Module {
) )
} }
async onEnable() { onEnable() {
/*const t = this,
React = await this.web_munch.findModule('react');
if ( ! React )
return;
//const createElement = React.createElement;*/
this.css_tweaks.toggle('channel-metadata-top', this.settings.get('channel.metadata.force-above')); this.css_tweaks.toggle('channel-metadata-top', this.settings.get('channel.metadata.force-above'));
this.ChannelBar.on('unmount', this.unmountChannelBar, this); this.ChannelBar.on('unmount', this.unmountChannelBar, this);
@ -75,59 +67,9 @@ export default class ChannelBar extends Module {
this.ChannelBar.on('update', this.updateChannelBar, this); this.ChannelBar.on('update', this.updateChannelBar, this);
this.ChannelBar.ready((cls, instances) => { this.ChannelBar.ready((cls, instances) => {
/*const old_render = cls.prototype.render;
cls.prototype.render = function() {
if ( this.props.channelIsHosting )
return null;
const title = this.getTitle();
return (<div
data-test-selector="channel-info-bar-wrapper"
class="channel-info-bar tw-border-b tw-border-bottom-left-radius-large tw-border-bottom-right-radius-large tw-border-l tw-border-r tw-border-t tw-flex tw-flex-wrap tw-justify-content-between tw-lg-pd-b-0 tw-lg-pd-t-1 tw-lg-pd-x-1 tw-pd-1"
>
<div class="channel-info-bar__content-container tw-flex tw-full-width tw-justify-content-between tw-mg-b-1">
<div class="tw-full-width">
<div class="tw-flex">
<div class="tw-flex tw-mg-t-05">
{this.renderGameBoxArt()}
</div>
<div class="channel-info-bar__content-right tw-full-width">
<div class="tw-flex tw-justify-content-between">
<div class="tw-ellipsis tw-mg-b-05 tw-mg-r-2">
<span
class="tw-font-size-4"
data-a-target="stream-title"
data-test-selector="channel-info-bar-title-text"
title={title}
>
{title}
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>);
}*/
for(const inst of instances) {
//inst.forceUpdate();
this.updateChannelBar(inst);
}
});
/*this.HostBar.on('unmount', this.unmountHostBar, this);
this.HostBar.on('mount', this.updateHostBar, this);
this.HostBar.on('update', this.updateHostBar, this);
this.HostBar.ready((cls, instances) => {
for(const inst of instances) for(const inst of instances)
this.updateHostBar(inst); this.updateChannelBar(inst);
});*/ });
} }

View file

@ -285,13 +285,13 @@ export default class EmoteMenu extends Module {
<t.MenuComponent <t.MenuComponent
visible={this.props.visible} visible={this.props.visible}
toggleVisibility={this.props.toggleVisibility} toggleVisibility={this.props.toggleVisibility}
onClickEmote={this.props.onClickEmote}
channel_data={this.props.channelData} channel_data={this.props.channelData}
emote_data={this.props.emoteSetsData} emote_data={this.props.emoteSetsData}
user_id={this.props.currentUserID} user_id={this.props.currentUserID}
channel_id={this.props.channelOwnerID} channel_id={this.props.channelOwnerID}
loading={this.state.gqlLoading} loading={this.state.gqlLoading}
error={this.state.gqlError} error={this.state.gqlError}
onClickEmote={this.props.onClickEmote}
/> />
</t.MenuErrorWrapper>) </t.MenuErrorWrapper>)
} }
@ -575,7 +575,7 @@ export default class EmoteMenu extends Module {
} }
} }
return (<section ref={this.saveRef} onMouseEnter={this.mouseEnter} data-key={data.key} class={filtered ? 'filtered' : ''}> return (<section ref={this.saveRef} data-key={data.key} class={filtered ? 'filtered' : ''} onMouseEnter={this.mouseEnter}>
{show_heading ? (<heading class="tw-pd-1 tw-border-b tw-flex tw-flex-nowrap" onClick={this.clickHeading}> {show_heading ? (<heading class="tw-pd-1 tw-border-b tw-flex tw-flex-nowrap" onClick={this.clickHeading}>
{image} {image}
<div class="tw-pd-l-05"> <div class="tw-pd-l-05">
@ -1690,8 +1690,6 @@ export default class EmoteMenu extends Module {
<input <input
type="text" type="text"
class="tw-block tw-border-radius-medium tw-font-size-6 tw-full-width tw-input tw-pd-x-1 tw-pd-y-05" class="tw-block tw-border-radius-medium tw-font-size-6 tw-full-width tw-input tw-pd-x-1 tw-pd-y-05"
onChange={this.handleFilterChange}
onKeyDown={this.handleKeyDown}
placeholder={ placeholder={
is_emoji ? is_emoji ?
t.i18n.t('emote-menu.search-emoji', 'Search for Emoji') : t.i18n.t('emote-menu.search-emoji', 'Search for Emoji') :
@ -1701,6 +1699,8 @@ export default class EmoteMenu extends Module {
autoFocus autoFocus
autoCapitalize="off" autoCapitalize="off"
autoCorrect="off" autoCorrect="off"
onChange={this.handleFilterChange}
onKeyDown={this.handleKeyDown}
/> />
{is_emoji && <t.EmojiTonePicker {is_emoji && <t.EmojiTonePicker
tone={this.state.tone} tone={this.state.tone}

View file

@ -383,6 +383,8 @@ export default class ChatHook extends Module {
for(const inst of this.ChatController.instances) for(const inst of this.ChatController.instances)
if ( inst && inst.chatService ) if ( inst && inst.chatService )
return inst; return inst;
return null;
} }

View file

@ -146,7 +146,7 @@ export default class ChatLine extends Module {
if ( ! this.ffz_user_click_handler ) if ( ! this.ffz_user_click_handler )
this.ffz_user_click_handler = this.props.onUsernameClick; this.ffz_user_click_handler = this.props.onUsernameClick;
let cls = `chat-line__message${show_class ? ' ffz--deleted-message' : ''}`, const cls = `chat-line__message${show_class ? ' ffz--deleted-message' : ''}`,
out = (tokens.length || ! msg.ffz_type) ? [ out = (tokens.length || ! msg.ffz_type) ? [
this.props.showTimestamps && e('span', { this.props.showTimestamps && e('span', {
className: 'chat-line__timestamp' className: 'chat-line__timestamp'

View file

@ -21,13 +21,13 @@ export default class BrowsePopular extends SiteModule {
this.apollo.registerModifier('BrowsePage_Popular', res => this.modifyStreams(res), false); this.apollo.registerModifier('BrowsePage_Popular', res => this.modifyStreams(res), false);
} }
onEnable() { /*onEnable() {
// Popular Directory Channel Cards // Popular Directory Channel Cards
/*this.apollo.ensureQuery( this.apollo.ensureQuery(
'BrowsePage_Popular', 'BrowsePage_Popular',
'data.streams.edges.0.node.createdAt' 'data.streams.edges.0.node.createdAt'
);*/ );
} }*/
modifyStreams(res) { // eslint-disable-line class-methods-use-this modifyStreams(res) { // eslint-disable-line class-methods-use-this
const edges = get('data.streams.edges', res); const edges = get('data.streams.edges', res);

View file

@ -233,11 +233,11 @@ export default class Directory extends SiteModule {
channel_url = `/${channel.login}`, channel_url = `/${channel.login}`,
game_url = game && `/directory/game/${stream.game.name}`, game_url = game && `/directory/game/${stream.game.name}`,
user_link = <a href={channel_url} data-href={channel_url} onClick={t.routeClick} title={channel.displayName} class="tw-link tw-link--inherit">{channel.displayName}</a>, user_link = <a href={channel_url} data-href={channel_url} title={channel.displayName} class="tw-link tw-link--inherit" onClick={t.routeClick}>{channel.displayName}</a>,
game_link = game && <a href={game_url} data-href={game_url} onClick={t.routeClick} title={game.name} class="tw-link tw-link--inherit">{game.name}</a>; game_link = game && <a href={game_url} data-href={game_url} title={game.name} class="tw-link tw-link--inherit" onClick={t.routeClick}>{game.name}</a>;
return (<div> return (<div>
<a href={channel_url} data-href={channel_url} onClick={t.routeClick} class="tw-link tw-link--inherit" data-test-selector="preview-card-titles__primary-link"> <a href={channel_url} data-href={channel_url} class="tw-link tw-link--inherit" data-test-selector="preview-card-titles__primary-link" onClick={t.routeClick}>
<h3 class="tw-ellipsis tw-font-size-5 tw-strong" title={stream.title}>{stream.title}</h3> <h3 class="tw-ellipsis tw-font-size-5 tw-strong" title={stream.title}>{stream.title}</h3>
</a> </a>
<div class="preview-card-titles__subtitle-wrapper"> <div class="preview-card-titles__subtitle-wrapper">
@ -261,7 +261,7 @@ export default class Directory extends SiteModule {
nodes.length > 1 ? nodes.length > 1 ?
t.i18n.t('directory.hosted.by-many', 'Hosted by {count,number} channel{count,en_plural}', nodes.length) : t.i18n.t('directory.hosted.by-many', 'Hosted by {count,number} channel{count,en_plural}', nodes.length) :
t.i18n.tList('directory.hosted.by-one', 'Hosted by {user}', { t.i18n.tList('directory.hosted.by-one', 'Hosted by {user}', {
user: <a href={`/${nodes[0].login}`} data-href={`/${nodes[0].login}`} onClick={t.routeClick} title={nodes[0].displayName} class="tw-link tw-link--inherit">{nodes[0].displayName}</a> user: <a href={`/${nodes[0].login}`} data-href={`/${nodes[0].login}`} title={nodes[0].displayName} class="tw-link tw-link--inherit" onClick={t.routeClick}>{nodes[0].displayName}</a>
}) })
}</p> }</p>
</div> </div>

View file

@ -32,7 +32,9 @@
<div class="ffz-channel-avatar"> <div class="ffz-channel-avatar">
<img :src="host.logo" :alt="host.display_name + '(' + host.name + ')'"> <img :src="host.logo" :alt="host.display_name + '(' + host.name + ')'">
</div> </div>
<p class="tw-ellipsis tw-flex-grow-1 tw-mg-l-1 tw-font-size-5">{{ host.name }}</p> <p class="tw-ellipsis tw-flex-grow-1 tw-mg-l-1 tw-font-size-5">
{{ host.name }}
</p>
<div class="tw-flex-grow-1 tw-pd-x-2" /> <div class="tw-flex-grow-1 tw-pd-x-2" />
<button class="tw-button-icon tw-mg-x-05 ffz--host-remove-user" @click="removeFromHosts"> <button class="tw-button-icon tw-mg-x-05 ffz--host-remove-user" @click="removeFromHosts">
<figure class="ffz-i-trash" /> <figure class="ffz-i-trash" />

View file

@ -777,5 +777,7 @@ export default class Player extends Module {
for(const inst of this.Player.instances) for(const inst of this.Player.instances)
if ( inst && inst.player ) if ( inst && inst.player )
return inst.player; return inst.player;
return null;
} }
} }

View file

@ -8,9 +8,9 @@
</div> </div>
<input <input
:id="_id" :id="_id"
v-model="search"
:placeholder="placeholder" :placeholder="placeholder"
:class="[hasIcon ? 'tw-pd-l-3' : 'tw-pd-l-1']" :class="[hasIcon ? 'tw-pd-l-3' : 'tw-pd-l-1']"
v-model="search"
type="search" type="search"
class="tw-block tw-border-radius-medium tw-font-size-6 tw-full-width tw-input tw-pd-r-1 tw-pd-y-05" class="tw-block tw-border-radius-medium tw-font-size-6 tw-full-width tw-input tw-pd-r-1 tw-pd-y-05"
autocapitalize="off" autocapitalize="off"
@ -43,8 +43,8 @@
</div> </div>
<button <button
v-for="(item, idx) of filteredItems" v-for="(item, idx) of filteredItems"
:key="has(item, 'id') ? item.id : idx"
:id="'ffz-autocomplete-item-' + id + '-' + idx" :id="'ffz-autocomplete-item-' + id + '-' + idx"
:key="has(item, 'id') ? item.id : idx"
:class="{'tw-interactable--hover' : idx === index}" :class="{'tw-interactable--hover' : idx === index}"
class="tw-block tw-full-width tw-interactable tw-interactable--inverted tw-interactive" class="tw-block tw-full-width tw-interactable tw-interactable--inverted tw-interactive"
tabindex="-1" tabindex="-1"
@ -125,6 +125,10 @@ export default {
type: String, type: String,
required: false, required: false,
default: 'down' default: 'down'
},
logger: {
type: Object,
required: false
} }
}, },
@ -227,7 +231,10 @@ export default {
try { try {
result = this.items(this.search); result = this.items(this.search);
} catch(err) { } catch(err) {
console.error(err); if ( this.logger )
this.logger.capture(err);
else
console.error(err); // eslint-disable-line no-console
} }
if ( result instanceof Promise ) { if ( result instanceof Promise ) {
@ -236,7 +243,11 @@ export default {
this.loading = false; this.loading = false;
this.cachedItems = items; this.cachedItems = items;
}).catch(err => { }).catch(err => {
console.error(err); if ( this.logger )
this.logger.capture(err);
else
console.error(err); // eslint-disable-line no-console
this.loading = false; this.loading = false;
this.errored = true; this.errored = true;
this.cachedItems = []; this.cachedItems = [];

View file

@ -20,8 +20,8 @@
> >
<div <div
v-for="(i, idx) in item.tabs" v-for="(i, idx) in item.tabs"
:key="i.full_key"
:id="'tab-for-' + i.full_key" :id="'tab-for-' + i.full_key"
:key="i.full_key"
:aria-selected="selected === idx" :aria-selected="selected === idx"
:aria-controls="'tab-panel-' + i.full_key" :aria-controls="'tab-panel-' + i.full_key"
:class="{'active': selected === idx, 'ffz-unmatched-item': showing && ! shouldShow(i)}" :class="{'active': selected === idx, 'ffz-unmatched-item': showing && ! shouldShow(i)}"