From 61ac0b97f6d868ffe828d190702d4c9713dc142b Mon Sep 17 00:00:00 2001
From: SirStendec
Date: Wed, 5 Apr 2017 19:12:11 -0400
Subject: [PATCH] 3.5.457. Commerce stuff. Favorite any emote. Consolidate
emotes from your Twitch Inventory. Dark CSS tweaks. Add emoji size settings.
Highlight messages with mentions without having alternating rows enabled.
---
changelog.html | 76 +++++---
credits.html | 1 +
dark.css | 38 +++-
old_changes.html | 58 ++++++
src/badges.js | 10 +-
src/constants.js | 5 +
src/ember/bits.js | 49 +++--
src/ember/commerce.js | 316 +++++++++++++++++++++++++++++++++
src/ember/line.js | 55 +++++-
src/ember/room.js | 3 -
src/emoticons.js | 65 ++++++-
src/featurefriday.js | 2 +-
src/less/dark-clips.less | 30 ++++
src/main.js | 4 +-
src/styles/chat-background.css | 63 -------
src/tokenize.js | 38 +++-
src/ui/menu.js | 27 +--
src/ui/my_emotes.js | 68 +++++--
src/ui/notifications.js | 13 +-
style.css | 69 ++++++-
20 files changed, 830 insertions(+), 160 deletions(-)
create mode 100644 src/ember/commerce.js
diff --git a/changelog.html b/changelog.html
index 682bc724..47ba71d3 100644
--- a/changelog.html
+++ b/changelog.html
@@ -1,59 +1,79 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
diff --git a/credits.html b/credits.html
index 18179f22..8a0be544 100644
--- a/credits.html
+++ b/credits.html
@@ -11,6 +11,7 @@
Possible Values: " + output.join(", "),
+ "Please enter a comma-separated list of badges that you would like to be hidden in chat. You can use the special value game
to hide all the game-specific badges at once.
Possible Values: " + output.join(", "),
old_val,
function(new_val) {
if ( new_val === null || new_val === undefined )
@@ -514,9 +514,10 @@ FFZ.prototype.get_twitch_badges = function(badge_tag, room_id) {
continue;
var versions = channel[badge] || globals[badge],
- binfo = versions && versions.versions && versions.versions[version];
+ binfo = versions && versions.versions && versions.versions[version],
+ is_game = badge.substr(-2) === '_1';
- if ( hidden_badges.indexOf(badge) !== -1 )
+ if ( hidden_badges.indexOf(badge) !== -1 || (is_game && hidden_badges.indexOf('game') !== -1) )
continue;
if ( BADGE_POSITIONS.hasOwnProperty(badge) )
@@ -648,7 +649,8 @@ FFZ.prototype.bttv_badges = function(data) {
hidden_key = hidden_key.substr(0, ind);
}
- if ( hidden_badges.indexOf(hidden_key) !== -1 ) {
+ var is_game = hidden_key.substr(-2) === '_1';
+ if ( hidden_badges.indexOf(hidden_key) !== -1 || (is_game && hidden_badges.indexOf('game') !== -1) ) {
data.badges.splice(i, 1);
i--;
continue;
diff --git a/src/constants.js b/src/constants.js
index acd39773..f9d73dc0 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -26,6 +26,11 @@ module.exports = FrankerFaceZ.constants = {
IS_WEBKIT: IS_WEBKIT,
META_NAME: IS_OSX ? "⌘" : (IS_WIN ? "Win" : "Meta"),
+ // ITAD Stuff
+ ITAD_SERVER: "https://api.isthereanydeal.com/",
+ ITAD_CLIENT_ID: "ffdd6ec4951be145",
+ ITAD_API_KEY: "43667479346a55e9b473f605a6b07ede02c8f3b2",
+
// Twitch Client ID for API Stuff
CLIENT_ID: "a3bc9znoz6vi8ozsoca0inlcr4fcvkl",
diff --git a/src/ember/bits.js b/src/ember/bits.js
index 1cfc8d87..c799f8be 100644
--- a/src/ember/bits.js
+++ b/src/ember/bits.js
@@ -90,21 +90,29 @@ FFZ.settings_info.bits_pinned = {
}
-FFZ.settings_info.bits_disable_charity = {
+FFZ.settings_info.bits_redesign = {
type: "boolean",
value: false,
- category: "Chat Filtering",
- name: "Disable Cheering with #Charity Notices",
- help: "Stop displaying Twitch's notices about Cheering with #Charity."
-}
+ category: "Chat Appearance",
+ name: "Bits Redesign",
+ help: "Use the special cheering animations from April 1st, 2017.",
+ on_update: function() {
+ var bits = utils.ember_lookup('service:bits-emotes') ||
+ utils.ember_lookup('service:bits-rendering-config');
+ if ( bits && bits.ffz_has_css )
+ bits.ffz_update_css();
+ }
+}
// --------------------
// Initialization
// --------------------
+var redesign = function(x) { return x.replace('/actions/cheer/', '/actions/cheer-redesign/') };
+
FFZ.prototype.setup_bits = function() {
utils.toggle_cls('ffz-show-bits-tags')(this.settings.bits_tags_container);
@@ -115,9 +123,19 @@ FFZ.prototype.setup_bits = function() {
PinnedCheers = utils.ember_lookup('service:bits-pinned-cheers'),
image_css = function(images) {
- return 'background-image: url("' + images[1] + '");' +
+ var im_1 = images[1],
+ im_2 = images[2],
+ im_4 = images[4];
+
+ if ( f.settings.bits_redesign ) {
+ im_1 = redesign(im_1);
+ im_2 = redesign(im_2);
+ im_4 = redesign(im_4);
+ }
+
+ return 'background-image: url("' + im_1 + '");' +
'background-image: ' + (constants.IS_WEBKIT ? ' -webkit-' : '') + 'image-set(' +
- 'url("' + images[1] + '") 1x, url("' + images[2] + '") 2x, url("' + images[4] + '") 4x);';
+ 'url("' + im_1 + '") 1x, url("' + im_2 + '") 2x, url("' + im_4 + '") 4x);';
},
tier_css = function(ind, prefix, tier) {
@@ -184,7 +202,8 @@ FFZ.prototype.setup_bits = function() {
},
ffz_get_preview: function(prefix, amount) {
- return this.getImageSrc(amount, prefix, true, !f.settings.bits_animated, 4);
+ var src = this.getImageSrc(amount, prefix, true, !f.settings.bits_animated, 4);
+ return f.settings.bits_redesign ? redesign(src) : src;
},
_ffz_image_css: image_css,
@@ -249,12 +268,14 @@ FFZ.prototype.setup_bits = function() {
ffz_get_preview: function(prefix, amount) {
var data = this.ffz_get_tier(prefix, amount),
- tier = data && data[1];
- return tier ? this._constructImageSrc([4], tier, {
- background: 'dark',
- scale: 4,
- state: f.settings.bits_animated ? 'animated' : 'static'
- }).src : '';
+ tier = data && data[1],
+ src = tier ? this._constructImageSrc([4], tier, {
+ background: 'dark',
+ scale: 4,
+ state: f.settings.bits_animated ? 'animated' : 'static'
+ }).src : '';
+
+ return f.settings.bits_redesign ? redesign(src) : src;
},
_ffz_image_css: image_css,
diff --git a/src/ember/commerce.js b/src/ember/commerce.js
new file mode 100644
index 00000000..a36458ff
--- /dev/null
+++ b/src/ember/commerce.js
@@ -0,0 +1,316 @@
+var FFZ = window.FrankerFaceZ,
+ utils = require('../utils'),
+ constants = require('../constants');
+
+
+// --------------------
+// Settings
+// --------------------
+
+FFZ.settings_info.show_commerce = {
+ type: "select",
+ options: {
+ 0: "Never",
+ 1: "When Revenue is Shared",
+ 2: "Always"
+ },
+
+ value: 2,
+ process_value: utils.process_int(0),
+
+ no_mobile: true,
+
+ category: "Commerce",
+ name: "Display Commerce Bar",
+ help: "Show the commerce bar under channels that allows you to purchase supported games.",
+
+ on_update: function(val) {
+ utils.toggle_cls('ffz-hide-purchase-game')(val === 0);
+ var views = utils.ember_views(),
+ ChannelBox = utils.ember_resolve('component:commerce/channel-box');
+
+ if ( ! ChannelBox )
+ return;
+
+ for(var key in views)
+ if ( views[key] instanceof ChannelBox )
+ try {
+ views[key].ffzUpdateVisibility();
+ } catch(err) { }
+ }
+}
+
+
+FFZ.settings_info.show_itad = {
+ type: "boolean",
+ value: true,
+
+ no_mobile: true,
+
+ category: "Commerce",
+ name: "Display Competitor Pricing",
+ help: "Add a button on the commerce bar with pricing from other stores.",
+
+ on_update: function(val) {
+ var views = utils.ember_views(),
+ BuyGameNow = utils.ember_resolve('component:commerce/buy-game-now');
+
+ if ( ! BuyGameNow )
+ return;
+
+ for(var key in views)
+ if ( views[key] instanceof BuyGameNow )
+ try {
+ views[key].ffzRenderPricing();
+ } catch(err) { }
+ }
+}
+
+
+// --------------------
+// Initialization
+// --------------------
+
+FFZ.prototype.setup_commerce = function() {
+ this._itad_game_to_plain = {};
+
+ // Styles
+ utils.toggle_cls('ffz-hide-purchase-game')(this.settings.show_commerce === 0);
+
+ // Ember Modifications
+ this.update_views('component:commerce/channel-box', this.modify_commerce_box);
+ this.update_views('component:commerce/buy-game-now', this.modify_buy_game_now);
+}
+
+
+// --------------------
+// Modifications
+// --------------------
+
+FFZ.prototype.modify_commerce_box = function(view) {
+ var f = this;
+ utils.ember_reopen_view(view, {
+ ffz_init: function() {
+ this.ffzUpdateVisibility();
+ },
+
+ ffzUpdateVisibility: function() {
+ var el = this.parentView.get('element'),
+ real_el = el && el.querySelector('.cmrc-channel-box');
+
+ if ( ! real_el )
+ ! this.isDestroyed && setTimeout(this.ffzUpdateVisibility.bind(this), 250);
+ else
+ real_el.classList.toggle('hidden', f.settings.show_commerce === 1 && ! this.get('showSupports'));
+
+ }.observes('showSupports')
+ })
+}
+
+
+FFZ.prototype.modify_buy_game_now = function(view) {
+ var f = this;
+ utils.ember_reopen_view(view, {
+ itad_plain: null,
+ itad_price: null,
+ twitch_geo: null,
+
+ ffz_init: function() {
+ //f.log("Buy-Game-New Component", this);
+ this.itad_count = 0;
+ this.ffzUpdateITADPlain();
+
+ var t = this;
+ Twitch.geo.then(function(data) {
+ t.set('twitch_geo', data && data.geo);
+ });
+ },
+
+ ffzTitle: function() {
+ // Do this because Twitch's ToS say you're not allowed to use data collected from
+ // the API to show users commercial offers. This extracts the game title from the
+ // page itself and not from any kind of JS API.
+
+ // Granted, they're probably more worried about automated chat spam and people
+ // sending spam to email addresses recovered from authenticated user profile requests.
+
+ var el;
+ if ( document.body.dataset.currentPath === 'directory.game-details' )
+ el = document.querySelector('.game-details__page-title');
+ else
+ el = document.querySelector('.card__info [data-tt_content="current_game"]');
+
+ var output = el ? _.pluck(_.filter(el.childNodes, function(x) { return x.nodeType === document.TEXT_NODE }), 'textContent').join(' ').trim() : null;
+
+ if ( ! output && this.itad_count < 50 ) {
+ var t = this;
+ setTimeout(function() {
+ t.itad_count += 1;
+ Ember.propertyDidChange(this, 'ffzTitle');
+ }, 250);
+ }
+
+ return output;
+
+ }.property(),
+
+ didReceiveAttrs: function() {
+ this._super();
+ Ember.propertyDidChange(this, 'ffzTitle');
+ },
+
+ ffzUpdateITADPlain: function() {
+ var title = this.get('ffzTitle'),
+ old_plain = this.get('itad_plain'),
+ plain = f._itad_game_to_plain[title] || null;
+
+ //f.log("Update ITAD Plain: " + title + " -- [" + plain + "]", this);
+
+ // If we already have the value, fetch it now.
+ if ( ! title || plain ) {
+ if ( old_plain !== plain )
+ this.set('itad_plain', plain);
+ return;
+ }
+
+ if ( old_plain )
+ this.set('itad_plain', null);
+
+ var t = this;
+ f.ws_send("get_itad_plain", title, function(success, data) {
+ if ( ! success ) return;
+
+ f._itad_game_to_plain[title] = data;
+ t.ffzUpdateITADPlain();
+ }, true);
+
+ }.observes('ffzTitle'),
+
+ ffzUpdateITADPrice: function() {
+ var t = this,
+ old_price = this.get('itad_price'),
+ geo = this.get('twitch_geo'),
+ plain = this.get('itad_plain');
+
+ if ( old_price && old_price[0] === plain )
+ return;
+
+ if ( ! plain || ! geo )
+ return this.set('itad_price', null);
+
+ this.set('itad_price', [plain, null]);
+ f.ws_send("get_itad_prices", [plain, geo], function(success, data) {
+ if ( ! success ) return;
+
+ t.set('itad_price', [plain, data]);
+ });
+
+ }.observes('itad_plain', 'twitch_geo'),
+
+
+ ffzRenderPricing: function() {
+ var t = this,
+ el = this.get('element'),
+ cont = el && el.querySelector('.ffz-price-info'),
+ btn_price,
+ data = this.get('itad_price');
+
+ if ( ! f.settings.show_itad || ! data || ! data[1] || ! data[1].list || ! data[1].list.length ) {
+ if ( cont )
+ jQuery(cont).remove();
+ return;
+ }
+
+ if ( ! cont ) {
+ cont = utils.createElement('div', 'ffz-price-info mg-l-1 balloon-wrapper');
+ btn_price = utils.createElement('span', 'ffz-price-num button__num-block pd-x-1 mg-1-0');
+
+ var btn = utils.createElement('button', 'button itad-button button--dropmenu',
+ utils.createElement('span', 'ffz-price-label inline-block pd-r-1', 'ITAD'));
+
+ btn.appendChild(btn_price);
+ cont.appendChild(btn);
+ el.appendChild(cont);
+
+ btn.addEventListener('click', function(event) {
+ t.ffzRenderPopup(event);
+ });
+
+ } else
+ btn_price = cont.querySelector('.ffz-price-num');
+
+ // Determine the cheapest price.
+ var sales = data[1].list,
+ cheapest = sales[0].price_new,
+
+ currency = data[1].currency,
+ formatter = new Intl.NumberFormat(undefined, (currency && currency.code) ? {style: 'currency', currency: currency.code, minimumFractionDigits: 2} : {minimumFractionDigits: 2});
+
+ btn_price.textContent = formatter.format(cheapest);
+
+ }.observes('itad_price'),
+
+ ffzRenderPopup: function(e) {
+ if ( e.button !== 0 || e.altKey || e.ctrlKey || e.shiftKey || e.metaKey )
+ return;
+
+ e.preventDefault();
+ e.stopPropagation();
+
+ var popup = f._popup ? f.close_popup() : f._last_popup,
+ t = this,
+ data = t.get('itad_price'),
+ el = this.get('element'),
+ cont = el && el.querySelector('.ffz-price-info');
+
+ if ( popup && popup.id === 'ffz-price-popup' || ! data || ! data[1] || ! data[1].list || ! data[1].list.length )
+ return;
+
+ var balloon = utils.createElement('div', 'itad-balloon balloon balloon--md show', '
Store | Price Cut | Current | Regular |
---|
'),
+ tbody = balloon.querySelector('tbody');
+
+ balloon.id = 'ffz-price-popup';
+
+ // Render the table.
+
+ var currency = data[1].currency,
+ formatter = new Intl.NumberFormat(undefined, (currency && currency.code) ? {style: 'currency', currency: currency.code, minimumFractionDigits: 2} : {minimumFractionDigits: 2});
+
+ var sales = data[1].list;
+ for(var i=0; i < sales.length; i++) {
+ var entry = sales[i],
+ row = utils.createElement('tr');
+
+ row.innerHTML = '' + utils.sanitize(entry.shop.name) + ' | ' +
+ '' + (entry.price_cut < 0 ? '' : '-') + utils.sanitize(entry.price_cut) + '% | ' +
+ '' + formatter.format(entry.price_new) + ' | ' +
+ '' + formatter.format(entry.price_old) + ' | ';
+
+ tbody.appendChild(row);
+ }
+
+ // Add a by-line for IsThereAnyDeal.
+
+ var url = data[1].urls && data[1].urls.game || "https://isthereanydeal.com",
+ by_line = utils.createElement('span', 'ffz-attribution', 'Source: IsThereAnyDeal.com
Any affiliate links in the provided data are the responsibility of IsThereAnyDeal.');
+
+ balloon.appendChild(by_line);
+
+
+ // Now calculate the position and add the balloon to the DOM.
+
+ var container = document.querySelector('#main_col'),
+ outer = container.getBoundingClientRect(),
+ rect = cont.getBoundingClientRect();
+
+ var is_up = (rect.top - outer.top) > (outer.bottom - rect.bottom);
+ balloon.classList.add('balloon--' + (is_up ? 'up' : 'down'));
+ balloon.classList.toggle('balloon--right', (rect.left - outer.left) > (outer.right - rect.right));
+
+ f._popup_allow_parent = true;
+ f._popup = balloon;
+
+ cont.appendChild(balloon);
+ }
+ })
+}
\ No newline at end of file
diff --git a/src/ember/line.js b/src/ember/line.js
index f876e0e0..a51dd497 100644
--- a/src/ember/line.js
+++ b/src/ember/line.js
@@ -346,17 +346,30 @@ FFZ.settings_info.image_hover_all_domains = {
FFZ.settings_info.chat_rows = {
- type: "boolean",
- value: false,
+ type: "select",
+ options: {
+ 0: "Disabled",
+ 1: "Alternating",
+ 2: "Red Highlights",
+ 3: "Both"
+ },
+
+ value: 0,
+ process_value: utils.process_int(0, 0, 3),
category: "Chat Appearance",
no_bttv: true,
name: "Chat Line Backgrounds",
- help: "Display alternating background colors for lines in chat.",
+ help: "Display alternating background colors for lines in chat or make messages with highlighted words red.",
on_update: function(val) {
- this.toggle_style('chat-background', !this.has_bttv && val);
+ if ( this.has_bttv )
+ val = 0;
+
+ this.toggle_style('chat-background', val === 1 || val === 3);
+ this.toggle_style('chat-mention-bg', val > 1);
+ this.toggle_style('chat-mention-bg-alt', val === 3);
}
};
@@ -527,6 +540,36 @@ FFZ.settings_info.chat_font_family = {
};
+FFZ.settings_info.emoji_scale = {
+ type: "select",
+ options: {
+ 0: "Scale with Text (Default)",
+ 1: "Old Default (18px)",
+ 2: "Emote Size (28px)"
+ },
+
+ value: 0,
+ process_value: utils.process_int(0),
+
+ category: "Chat Appearance",
+ no_bttv: true,
+
+ name: "Emoji Size",
+ help: "Make emoji in chat bigger or smaller.",
+
+ on_update: function(val) {
+ var size = 18;
+ if ( val === 0 )
+ size = 1.5 * this.settings.chat_font_size;
+ else if ( val === 2 )
+ size = 28;
+
+ utils.update_css(this._chat_style, 'emoji_size',
+ size !== 18 ? '.chat-line .emoji{height:' + size + 'px}' : '');
+ }
+}
+
+
FFZ.settings_info.chat_font_size = {
type: "button",
value: 12,
@@ -567,6 +610,7 @@ FFZ.settings_info.chat_font_size = {
else {
var lh = Math.max(20, Math.round((20/12)*val)),
pd = Math.floor((lh - 20) / 2);
+
css = ".pinned-cheers .chat-line,.timestamp-line,.conversation-chat-line,.conversation-system-messages,.chat-history .chat-line,.ember-chat .chat-messages .chat-line { font-size: " + val + "px !important; line-height: " + lh + "px !important; }";
if ( pd )
css += ".pinned-cheers .chat-line,.ember-chat .chat-messages .chat-line .mod-icons, .ember-chat .chat-messages .chat-line .badges { padding-top: " + pd + "px; }";
@@ -574,6 +618,7 @@ FFZ.settings_info.chat_font_size = {
utils.update_css(this._chat_style, "chat_font_size", css);
FFZ.settings_info.chat_ts_size.on_update.call(this, this.settings.chat_ts_size);
+ FFZ.settings_info.emoji_scale.on_update.call(this, this.settings.emoji_scale);
}
};
@@ -664,7 +709,7 @@ FFZ.prototype.setup_line = function() {
utils.toggle_cls('ffz-baseline-emoticons')(!this.has_bttv && this.settings.emote_alignment === 2);
this.toggle_style('chat-padding', !this.has_bttv && this.settings.chat_padding);
- this.toggle_style('chat-background', !this.has_bttv && this.settings.chat_rows);
+ FFZ.settings_info.chat_rows.on_update.call(this, this.settings.chat_rows);
this.toggle_style('chat-separator', !this.has_bttv && this.settings.chat_separators);
this.toggle_style('chat-separator-3d', !this.has_bttv && this.settings.chat_separators === 2);
diff --git a/src/ember/room.js b/src/ember/room.js
index f417aec5..d105a5df 100644
--- a/src/ember/room.js
+++ b/src/ember/room.js
@@ -2112,9 +2112,6 @@ FFZ.prototype._modify_room = function(room) {
notice_type = msg.tags && msg.tags['msg-id'],
is_whisper = msg.style === 'whisper';
- if ( notice_type === 'charity' && f.settings.bits_disable_charity )
- return;
-
// If this message is already in the room, discard the duplicate.
if ( msg_id && this.ffz_ids && this.ffz_ids[msg_id] )
return;
diff --git a/src/emoticons.js b/src/emoticons.js
index 61c3c020..3347ea34 100644
--- a/src/emoticons.js
+++ b/src/emoticons.js
@@ -4,6 +4,8 @@ var FFZ = window.FrankerFaceZ,
constants = require('./constants'),
utils = require('./utils'),
+ IS_OSX = constants.IS_OSX,
+
MODIFIERS = {
59847: {
modifier_offset: '0 15px 15px 0',
@@ -116,7 +118,68 @@ FFZ.prototype._report_emotes = function() {
// ------------------------
FFZ.prototype._click_emote = function(target, event) {
- if ( ! this.settings.clickable_emoticons || (event && !((event.shiftKey || event.shiftLeft) && target && target.classList.contains('emoticon'))) )
+ if ( ! target || ! target.classList.contains('emoticon') )
+ return;
+
+ if ( event && ((!IS_OSX && event.ctrlKey) || (IS_OSX && event.metaKey)) ) {
+ var eid, favorite_key;
+
+ if ( target.classList.contains('emoji') ) {
+ var emoji = target.getAttribute('data-ffz-emoji'),
+ emoji_data = this.emoji_data[emoji];
+
+ if ( emoji_data ) {
+ favorite_key = 'emoji';
+ eid = emoji_data.raw;
+ }
+
+ } else {
+ eid = target.getAttribute('data-emote');
+
+ if ( eid ) {
+ eid = parseInt(eid);
+ var twitch_set = this._twitch_emote_to_set[eid];
+ if ( twitch_set ) {
+ var Chat = utils.ember_lookup('controller:chat'),
+ tmi = Chat && Chat.get('currentRoom.tmiSession'),
+ twitch_sets = (tmi && tmi.getEmotes() || {'emoticon_sets': {}})['emoticon_sets'];
+
+ if ( twitch_sets[twitch_set] ) {
+ var set = twitch_sets[twitch_set];
+ if ( set.length === 1 && ! this._twitch_set_to_channel[twitch_set] )
+ favorite_key = 'twitch-inventory';
+ else
+ favorite_key = 'twitch-' + twitch_set;
+ }
+ }
+
+ } else {
+ eid = parseInt(target.getAttribute('data-ffz-emote'));
+ var set_id = target.getAttribute('data-ffz-set'),
+ emote_set = set_id && this.emote_sets[set_id];
+
+ if ( emote_set && emote_set.emoticons && emote_set.emoticons[eid] )
+ favorite_key = 'ffz-' + (emote_set.hasOwnProperty('source_ext') ? 'ext-' + emote_set.source_ext + '-' + set.source_id : set_id);
+ }
+ }
+
+ if ( favorite_key ) {
+ var favs = this.settings.favorite_emotes[favorite_key] = this.settings.favorite_emotes[favorite_key] || [],
+ is_favorited = favs.indexOf(eid) !== -1;
+
+ if ( is_favorited )
+ favs.removeObject(eid);
+ else
+ favs.push(eid);
+
+ this.settings.set("favorite_emotes", this.settings.favorite_emotes, true);
+ jQuery(target).trigger('mouseout').trigger('mouseover');
+ }
+
+ return true;
+ }
+
+ if ( ! this.settings.clickable_emoticons || (event && !(event.shiftKey || event.shiftLeft)) )
return;
var eid = target.getAttribute('data-emote');
diff --git a/src/featurefriday.js b/src/featurefriday.js
index 36642616..a8d79ea3 100644
--- a/src/featurefriday.js
+++ b/src/featurefriday.js
@@ -48,7 +48,7 @@ FFZ.prototype._feature_friday_ui = function(room_id, parent, view) {
if ( ! this.feature_friday || this.feature_friday.channel === room_id )
return;
- this._emotes_for_sets(parent, view, [this.feature_friday.set], this.feature_friday.title, this.feature_friday.icon, "FrankerFaceZ");
+ this._emotes_for_set(parent, view, this.feature_friday.set, this.feature_friday.title, this.feature_friday.icon, "FrankerFaceZ");
// Before we add the button, make sure the channel isn't the
// current channel.
diff --git a/src/less/dark-clips.less b/src/less/dark-clips.less
index efe1b9d6..ced59db1 100644
--- a/src/less/dark-clips.less
+++ b/src/less/dark-clips.less
@@ -52,6 +52,27 @@
}
+ .view-clip__meta-wrapper {
+ background-color: @nav-bg-color;
+ }
+
+ .view-clip__actions,
+ .view-clip__bc {
+ border-color: lighten(@nav-bg-color, 10%);
+ }
+
+ .view-clip__title {
+ color: @fg-color;
+ }
+
+ .emote-picker {
+ background-color: @nav-bg-color;
+ }
+
+ .emote-picker__emotes .reaction__emote:hover {
+ background-color: lighten(@nav-bg-color, 10%);
+ }
+
.yin-alert {
background-color: lighten(@nav-bg-color, 10%);
@@ -103,6 +124,10 @@
// Buttons
+ .emote-picker__trigger {
+ fill: @link-color;
+ }
+
.button {
&, &:hover, &:focus {
color: #fff;
@@ -214,6 +239,11 @@
}
+ .form__input {
+ background-color: fade(white, 5%);
+ color: lighten(@fg-color, 10%);
+ border-color: fade(white, 10%);
+ }
.cf-textarea-input {
background-color: fade(white, 5%);
diff --git a/src/main.js b/src/main.js
index 7046b931..12b2898b 100644
--- a/src/main.js
+++ b/src/main.js
@@ -61,7 +61,7 @@ FFZ.channel_metadata = {};
// Version
var VER = FFZ.version_info = {
- major: 3, minor: 5, revision: 444,
+ major: 3, minor: 5, revision: 457,
toString: function() {
return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || "");
}
@@ -253,6 +253,7 @@ require('./ember/following');
require('./ember/feed-card');
require('./ember/sidebar');
require('./ember/dashboard');
+require('./ember/commerce');
require('./debug');
@@ -563,6 +564,7 @@ FFZ.prototype.init_ember = function(delay) {
this.setup_feed_cards();
this.setup_sidebar();
this.setup_dashboard();
+ this.setup_commerce();
//this.setup_teams();
diff --git a/src/styles/chat-background.css b/src/styles/chat-background.css
index 1a58485b..38d99932 100644
--- a/src/styles/chat-background.css
+++ b/src/styles/chat-background.css
@@ -89,69 +89,6 @@
}
-
-
-/* DEPRECIATED: Mention Backgrounds */
-.chat-line.ffz-mentioned {
- background-color: rgba(255,127,127,0.2);
-}
-
-.chat-lines > div:nth-child(2n+0) > .chat-line.ffz-mentioned,
-
-.chat-line.ffz-mentioned:nth-child(2n+0) {
- background-color: rgba(255,127,127, 0.4);
-}
-
-
-/* DEPRECIATED: DARK THEME: Mention Backgrounds */
-.ffz-dark .chat-history .chat-line.ffz-mentioned,
-
-.theatre .chat-line.ffz-mentioned,
-.dark .chat-line.ffz-mentioned {
- background-color: rgba(255,0,0, 0.2) !important;
-}
-
-.theatre .chat-lines > div:nth-child(2n+0) > .chat-line.ffz-mentioned,
-.dark .chat-lines > div:nth-child(2n+0) > .chat-line.ffz-mentioned,
-
-.ffz-dark .chat-history .chat-line.ffz-mentioned:nth-child(2n+0),
-.theatre .chat-line.ffz-mentioned:nth-child(2n+0),
-.dark .chat-line.ffz-mentioned:nth-child(2n+0) {
- background-color: rgba(255,0,0, 0.3) !important;
-}
-
-
-
-/* Chat Mentions */
-/* TODO: Move this by itself */
-
-.mentioned:empty,
-.mentioning:empty {
- display: none;
-}
-
-.chat-line .mentioned,
-.chat-line .mentioning {
- border-radius: 10px;
- padding: 3px 7px;
- font-weight: bold;
- color: #323232;
- background-color: rgba(255,255,255, 0.75);
-}
-
-/* DARK THEME: Chat Mentions */
-.ffz-dark .chat-history .mentioned,
-.ffz-dark .chat-history .mentioning,
-
-.chat-container.dark .chat-line .mentioned,
-.ember-chat-container.dark .chat-line .mentioned,
-.chat-container.dark .chat-line .mentioning,
-.ember-chat-container.dark .chat-line .mentioning {
- color: #8c8c8c;
- background-color: rgba(16,16,16, 0.75);
-}
-
-
/* Fix Conversations */
.conversation-window .timestamp-line span,
diff --git a/src/tokenize.js b/src/tokenize.js
index d0f56936..2f296bcb 100644
--- a/src/tokenize.js
+++ b/src/tokenize.js
@@ -10,6 +10,8 @@ var FFZ = window.FrankerFaceZ,
HOP = Object.prototype.hasOwnProperty,
+ FAV_MARKER = '',
+
EXPLANATION_WARN = '
This link has been sent to you via a whisper rather than standard chat, and has not been checked or approved of by any moderators or staff members. Please treat this link with caution and do not visit it if you do not trust the sender.',
reg_escape = function(str) {
@@ -416,7 +418,9 @@ FFZ.prototype.render_tooltip = function(el) {
return image + out;
} else if ( this.classList.contains('emoticon') ) {
- var preview_url, width=0, height=0, image, set_id, emote, emote_set,
+ var can_favorite = this.classList.contains('ffz-can-favorite'),
+
+ preview_url, width=0, height=0, image, set_id, emote, emote_set,
emote_id = this.getAttribute('data-ffz-emote'),
modifiers = this.getAttribute('data-modifier-info'),
mod_text = '';
@@ -438,6 +442,10 @@ FFZ.prototype.render_tooltip = function(el) {
emote = emote_set && emote_set.emoticons[emote_id];
if ( emote ) {
+ var favorite_key = 'ffz-' + (emote_set.hasOwnProperty('source_ext') ? 'ext-' + emote_set.source_ext + '-' + emote_set.source_id : emote_set.id),
+ favorites = f.settings.favorite_emotes[favorite_key] || [],
+ is_favorite = ! can_favorite && favorites.indexOf(emote && emote.id) !== -1;
+
var owner = emote.owner,
title = emote_set.title || "Global",
source = emote_set.source || "FFZ",
@@ -463,7 +471,7 @@ FFZ.prototype.render_tooltip = function(el) {
//image = preview_url ? `
` : '';
image = preview_url ? '
' : '';
- return image + 'Emoticon: ' + (emote.hidden ? '???' : utils.sanitize(emote.name)) + '
' + source_line + (owner ? '
By: ' + utils.sanitize(owner.display_name) : '') + mod_text;
+ return (is_favorite ? FAV_MARKER : '') + image + 'Emoticon: ' + (emote.hidden ? '???' : utils.sanitize(emote.name)) + '
' + source_line + (owner ? '
By: ' + utils.sanitize(owner.display_name) : '') + mod_text;
//return `${image}Emoticon: ${emote.hidden ? '???' : emote.name}
${source} ${title}${owner ? '
By: ' + owner.display_name : ""}`;
}
@@ -473,7 +481,22 @@ FFZ.prototype.render_tooltip = function(el) {
if ( emote_id ) {
set_id = f._twitch_emote_to_set[emote_id];
emote_set = set_id && f._twitch_set_to_channel[set_id];
- var set_type = "Channel";
+
+ var set_type = "Channel",
+ favorite_key = 'twitch-' + set_id,
+
+ Chat = utils.ember_lookup('controller:chat'),
+ tmi = Chat && Chat.get('currentRoom.tmiSession'),
+ twitch_sets = (tmi && tmi.getEmotes() || {'emoticon_sets': {}})['emoticon_sets'];
+
+ if ( ! emote_set && twitch_sets[set_id] ) {
+ var set = twitch_sets[set_id];
+ if ( set.length === 1 )
+ favorite_key = 'twitch-inventory';
+ }
+
+ var favorites = set_id && f.settings.favorite_emotes[favorite_key] || [],
+ is_favorite = ! can_favorite && favorites.indexOf(parseInt(emote_id)) !== -1;
preview_url = f.settings.emote_image_hover && (constants.TWITCH_BASE + emote_id + '/3.0');
//image = preview_url ? `
` : '';
@@ -492,9 +515,9 @@ FFZ.prototype.render_tooltip = function(el) {
}
if ( this.classList.contains('ffz-tooltip-no-credit') )
- return image + utils.sanitize(this.alt) + mod_text;
+ return (is_favorite ? FAV_MARKER : '') + image + utils.sanitize(this.alt) + mod_text;
else
- return image + 'Emoticon: ' + utils.sanitize(this.alt) + '
' + (set_type ? set_type + ': ' : '') + emote_set + mod_text;
+ return (is_favorite ? FAV_MARKER : '') + image + 'Emoticon: ' + utils.sanitize(this.alt) + '
' + (set_type ? set_type + ': ' : '') + emote_set + mod_text;
//return `${image}Emoticon: ${this.alt}
${set_type ? set_type + ": " : ""}${emote_set}`;
}
@@ -503,11 +526,14 @@ FFZ.prototype.render_tooltip = function(el) {
emote = f.emoji_data[emote_id];
var src = emote && (f.settings.parse_emoji === 3 ? emote.one_src : (f.settings.parse_emoji === 2 ? emote.noto_src : emote.tw_src));
+ var favorites = f.settings.favorite_emotes.emoji || [],
+ is_favorite = ! can_favorite && favorites.indexOf(emote.raw) !== -1;
+
preview_url = f.settings.emote_image_hover && src;
//image = preview_url ? `
` : '';
image = preview_url ? '
' : '';
- return image + "Emoji: " + this.alt + '
Name: ' + emote.name + (emote.short_name ? '
Short Name :' + emote.short_name + ':' : '') + (emote.cat ? '
Category: ' + utils.sanitize(constants.EMOJI_CATEGORIES[emote.cat] || emote.cat) : '') + mod_text;
+ return (is_favorite ? FAV_MARKER : '') + image + "Emoji: " + this.alt + '
Name: ' + emote.name + (emote.short_name ? '
Short Name :' + emote.short_name + ':' : '') + (emote.cat ? '
Category: ' + utils.sanitize(constants.EMOJI_CATEGORIES[emote.cat] || emote.cat) : '') + mod_text;
//return `${image}Emoji: ${this.alt}
Name: ${emote.name}${emote.short_name ? '
Short Name: :' + emote.short_name + ':' : ''}`;
}
diff --git a/src/ui/menu.js b/src/ui/menu.js
index f6f86679..e1450d32 100644
--- a/src/ui/menu.js
+++ b/src/ui/menu.js
@@ -604,7 +604,7 @@ FFZ.menu_pages.channel = {
var extra_sets = _.union(room && room.extra_sets || [], room && room.ext_sets || [], []);
// Basic Emote Sets
- this._emotes_for_sets(inner, view, room && room.set && [room.set] || [], (this.feature_friday || has_product || extra_sets.length ) ? "Channel Emoticons" : null, (room && room.moderator_badge) || "//cdn.frankerfacez.com/script/devicon.png", "FrankerFaceZ", ! has_product && extra_sets.length);
+ this._emotes_for_set(inner, view, room && room.set, (this.feature_friday || has_product || extra_sets.length ) ? "Channel Emoticons" : null, (room && room.moderator_badge) || "//cdn.frankerfacez.com/script/devicon.png", "FrankerFaceZ", ! has_product && extra_sets.length);
for(var i=0; i < extra_sets.length; i++) {
// Look up the set name.
@@ -614,7 +614,7 @@ FFZ.menu_pages.channel = {
if ( ! set || ! set.count || set.hidden )
continue;
- this._emotes_for_sets(inner, view, [extra_sets[i]], name, set.icon || "//cdn.frankerfacez.com/script/devicon.png", set.source || "FrankerFaceZ");
+ this._emotes_for_set(inner, view, extra_sets[i], name, set.icon || "//cdn.frankerfacez.com/script/devicon.png", set.source || "FrankerFaceZ");
}
// Feature Friday!
@@ -630,8 +630,10 @@ FFZ.menu_pages.channel = {
// Emotes for Sets
// --------------------
-FFZ.prototype._emotes_for_sets = function(parent, view, sets, header, image, sub_text, top_set) {
- var grid = document.createElement('div'), c = 0, f = this;
+FFZ.prototype._emotes_for_set = function(parent, view, set_id, header, image, sub_text, top_set) {
+ var grid = document.createElement('div'), c = 0, f = this,
+ set = this.emote_sets[set_id];
+
grid.className = 'emoticon-grid';
if ( top_set )
grid.classList.add('top-set');
@@ -659,18 +661,13 @@ FFZ.prototype._emotes_for_sets = function(parent, view, sets, header, image, sub
}
var emotes = [];
- for(var i=0; i < sets.length; i++) {
- var set = this.emote_sets[sets[i]];
- if ( ! set || ! set.emoticons )
- continue;
-
+ if ( set && set.emoticons )
for(var eid in set.emoticons) {
if ( ! set.emoticons.hasOwnProperty(eid) || set.emoticons[eid].hidden )
continue;
emotes.push(set.emoticons[eid]);
}
- }
// Sort the emotes!
emotes.sort(function(a,b) {
@@ -682,6 +679,10 @@ FFZ.prototype._emotes_for_sets = function(parent, view, sets, header, image, sub
return 0;
});
+ // Favoriting Info
+ var favorite_key = set ? 'ffz-' + (set.hasOwnProperty('source_ext') ? 'ext-' + set.source_ext + '-' + set.source_id : set.id) : undefined,
+ favorites = this.settings.favorite_emotes[favorite_key] || [];
+
for(var i=0; i < emotes.length; i++) {
var emote = emotes[i], srcset = null;
@@ -695,7 +696,9 @@ FFZ.prototype._emotes_for_sets = function(parent, view, sets, header, image, sub
c++;
var s = document.createElement('span');
- s.className = 'emoticon ffz-tooltip';
+ s.className = 'emoticon ffz-tooltip ffz-can-favorite';
+ if ( favorites.indexOf(emote.id) !== -1 )
+ s.classList.add('ffz-favorite');
s.setAttribute('data-ffz-emote', emote.id);
s.setAttribute('data-ffz-set', set.id);
@@ -726,7 +729,7 @@ FFZ.prototype._emotes_for_sets = function(parent, view, sets, header, image, sub
if ( url )
window.open(url);
} else
- this._add_emote(view, code);
+ this._add_emote(view, code, favorite_key, id, e);
}.bind(this, emote.id, emote.name));
grid.appendChild(s);
diff --git a/src/ui/my_emotes.js b/src/ui/my_emotes.js
index 21ea6782..d9358556 100644
--- a/src/ui/my_emotes.js
+++ b/src/ui/my_emotes.js
@@ -80,6 +80,7 @@ FFZ.settings_info.favorite_emotes = {
FFZ.prototype.setup_my_emotes = function() {
this._twitch_badges = {};
+ this._twitch_badges["--inventory--"] = "//cdn.frankerfacez.com/script/inventory_icon.svg";
this._twitch_badges["--global--"] = "//cdn.frankerfacez.com/script/twitch_logo.png";
this._twitch_badges["--turbo-faces--"] = this._twitch_badges["turbo"] = "//cdn.frankerfacez.com/script/turbo_badge.png";
this._twitch_badges["--prime-faces--"] = this._twitch_badges["--prime--"] = "//cdn.frankerfacez.com/badges/twitch/premium/1/1.png";
@@ -139,7 +140,7 @@ FFZ.menu_pages.myemotes = {
var el = document.createElement("div");
el.className = "emoticon-grid ffz-no-emotes center";
- el.innerHTML = "You have no favorite emoticons.

To make an emote a favorite, find it on the All Emoticons tab and " + (constants.IS_OSX ? '⌘' : 'Ctrl') + "-Click it.";
+ el.innerHTML = "You have no favorite emoticons.

To make an emote a favorite, find it and " + (constants.IS_OSX ? '⌘' : 'Ctrl') + "-Click it.";
container.appendChild(el);
}
},
@@ -194,28 +195,38 @@ FFZ.menu_pages.myemotes = {
user = this.get_user(),
ffz_sets = this.getEmotes(user && user.login, null),
- sets = [];
+ sets = [],
+ gathered_emotes = [];
// Start with Twitch Sets
+ var gathered_favorites = this.settings.favorite_emotes['twitch-inventory'] || [];
+
for(var set_id in twitch_sets) {
- if ( ! twitch_sets.hasOwnProperty(set_id) || ( ! this.settings.global_emotes_in_menu && set_id === '0' ) )
+ if ( ! twitch_sets.hasOwnProperty(set_id) || ( ! favorites_only && ! this.settings.global_emotes_in_menu && set_id === '0' ) )
continue;
// Skip the Twitch Turbo set if we have Twitch Prime. They're identical.
if ( set_id == 793 && twitch_sets.hasOwnProperty(19194) )
continue;
- var favorites_list = this.settings.favorite_emotes["twitch-" + set_id];
- if ( favorites_only && (! favorites_list || ! favorites_list.length) )
- continue;
-
var set = twitch_sets[set_id];
if ( ! set.length )
continue;
var raw_id = this._twitch_set_to_channel[set_id],
- menu_id = raw_id ? raw_id.toLowerCase() : 'unknown',
- sort_key = 0,
+ menu_id = raw_id ? raw_id.toLowerCase() : 'unknown';
+
+ if ( set.length === 1 && ! raw_id ) {
+ if ( ! favorites_only || gathered_favorites.indexOf(set[0].id) !== -1 )
+ gathered_emotes.push(set[0]);
+ continue;
+ }
+
+ var favorites_list = this.settings.favorite_emotes["twitch-" + set_id];
+ if ( favorites_only && (! favorites_list || ! favorites_list.length) )
+ continue;
+
+ var sort_key = 0,
menu = FFZ.menu_pages.myemotes.draw_twitch_set.call(this, view, set_id, set, favorites_only);
if ( menu_id.indexOf('global') !== -1 )
@@ -227,6 +238,13 @@ FFZ.menu_pages.myemotes = {
sets.push([[sort_key, menu_id], menu]);
}
+ // Handle the gathered single emotes.
+ if ( gathered_emotes.length ) {
+ var menu = FFZ.menu_pages.myemotes.draw_twitch_set.call(this, view, 'inventory', gathered_emotes, favorites_only);
+ sets.push([[50, 'twitch-inventory'], menu]);
+ }
+
+
// Emoji~!
if ( favorites_only && this.settings.emoji_in_menu ) {
var favorites_list = this.settings.favorite_emotes["emoji"];
@@ -238,10 +256,25 @@ FFZ.menu_pages.myemotes = {
}
// Now, FFZ!
+ if ( favorites_only ) {
+ // But first, inject all the sets from this specific room.
+ var ffz_room = controller && this.rooms && this.rooms[controller.get('currentRoom.id')];
+ if ( ffz_room ) {
+ if ( ffz_room.set && ffz_sets.indexOf(ffz_room.set) === -1 )
+ ffz_sets.push(ffz_room.set);
+
+ if ( ffz_room.sets && ffz_room.sets.length )
+ ffz_sets = _.uniq(ffz_sets.concat(ffz_room.sets));
+
+ if ( ffz_room.extra_sets && ffz_room.extra_sets.length )
+ ffz_sets = _.uniq(ffz_sets.concat(ffz_room.extra_sets));
+ }
+ }
+
for(var i=0; i < ffz_sets.length; i++) {
var set_id = ffz_sets[i],
set = this.emote_sets[set_id];
- if ( ! set || ! set.count || set.hidden || ( ! this.settings.global_emotes_in_menu && this.default_sets.indexOf(set_id) !== -1 ) )
+ if ( ! set || ! set.count || set.hidden || ( ! favorites_only && ! this.settings.global_emotes_in_menu && this.default_sets.indexOf(set_id) !== -1 ) )
continue;
var menu_id = set.hasOwnProperty('source_ext') ? 'ffz-ext-' + set.source_ext + '-' + set.source_id : 'ffz-' + set.id,
@@ -415,7 +448,7 @@ FFZ.menu_pages.myemotes = {
collapsed = ! favorites_only && this.settings.emote_menu_collapsed.indexOf('twitch-' + set_id) === -1,
f = this,
- channel_id = this._twitch_set_to_channel[set_id] || 'twitch_unknown', title,
+ channel_id = set_id === 'inventory' ? '--inventory--' : (this._twitch_set_to_channel[set_id] || 'twitch_unknown'), title,
favorites = this.settings.favorite_emotes["twitch-" + set_id] || [],
c = 0;
@@ -423,7 +456,9 @@ FFZ.menu_pages.myemotes = {
menu.setAttribute('data-set', 'twitch-' + set_id);
if ( ! favorites_only ) {
- if ( channel_id === "twitch_unknown" )
+ if ( channel_id === '--inventory--' )
+ title = "Inventory";
+ else if ( channel_id === "twitch_unknown" )
title = "Unknown Channel";
else if ( channel_id === "--global--" )
title = "Global Emoticons";
@@ -441,9 +476,12 @@ FFZ.menu_pages.myemotes = {
heading.className = 'heading';
heading.innerHTML = 'Twitch' + utils.sanitize(title);
- if ( this._twitch_badges[channel_id] )
- heading.style.backgroundImage = 'url("' + this._twitch_badges[channel_id] + '")';
- else {
+ var icon = this._twitch_badges[channel_id];
+ if ( icon ) {
+ heading.style.backgroundImage = 'url("' + icon + '")';
+ if ( icon.indexOf('.svg') !== -1 )
+ heading.style.backgroundSize = "18px";
+ } else {
var f = this;
utils.api.get("chat/" + channel_id + "/badges", null, {version: 3})
.done(function(data) {
diff --git a/src/ui/notifications.js b/src/ui/notifications.js
index acb46ab1..8c7226bb 100644
--- a/src/ui/notifications.js
+++ b/src/ui/notifications.js
@@ -76,17 +76,20 @@ FFZ.settings_info.notification_timeout = {
help: "Specify how long notifications should be displayed before automatically closing.",
method: function() {
- var f = this;
+ var f = this,
+ old_val = this.settings.notification_timeout;
utils.prompt(
"Notification Timeout",
- "Please enter the time you'd like notifications to be displayed before automatically closing, in seconds.Default: 60",
- this.settings.notification_timeout,
+ "Please enter the time you'd like notifications to be displayed before automatically closing, in seconds. A value of zero may prevent notifications from disappearing automatically. This value is subject to the limitations of your web browser.
Default: 60",
+ old_val === false ? 0 : old_val,
function(new_val) {
if ( new_val === null || new_val === undefined )
return;
new_val = parseInt(new_val);
- if ( Number.isNaN(new_val) || ! Number.isFinite(new_val) || new_val < 1 )
+ if ( new_val <= 0 )
+ new_val = false;
+ else if ( Number.isNaN(new_val) || ! Number.isFinite(new_val) )
new_val = 60;
f.settings.set("notification_timeout", new_val);
@@ -135,7 +138,7 @@ FFZ.prototype.show_notification = function(message, title, tag, timeout, on_clic
if ( perm === "granted" ) {
title = title || "FrankerFaceZ";
- timeout = timeout || (this.settings.notification_timeout*1000);
+ timeout = timeout || (this.settings.notification_timeout === false ? false : this.settings.notification_timeout * 1000);
var options = {
lang: "en-US",
diff --git a/style.css b/style.css
index 1824ea0d..aefc218f 100644
--- a/style.css
+++ b/style.css
@@ -34,6 +34,7 @@ body > div.tipsy .tipsy-arrow { opacity: 0.8; }
body:not(.ffz-theater-basic-stats) .player-userinfo__game,
body:not(.ffz-theater-basic-stats) .player-controls-top,
.moderation-card__actions:not(.loading):empty,
+.ffz-hide-purchase-game .cmrc-channel-box,
.ffz-minimal-dashboard[data-current-path="user.dashboards.index"] #left_col,
.ffz-minimal-dashboard[data-current-path="user.dashboards.index"] #left_close,
.ffz-minimal-dashboard[data-current-path="user.dashboards.index"] #right_col,
@@ -615,6 +616,7 @@ body.ffz-bttv-dark .ffz-ui-toggle.blue.live:hover svg.svg-emoticons path { fill:
.favorites-grid:not(:empty) + .ffz-no-emotes,
.favorites-grid .emoticon.ffz-favorite:before { display: none }
+.tipsy .ffz-favorite,
.suggestion.ffz-favorite:before,
.emoticon.ffz-favorite:before {
content: "";
@@ -625,6 +627,8 @@ body.ffz-bttv-dark .ffz-ui-toggle.blue.live:hover svg.svg-emoticons path { fill:
background: url("//cdn.frankerfacez.com/script/emoticon_favorite.png") no-repeat;
}
+.tipsy .ffz-favorite { right: 10px; bottom: 10px }
+
.suggestion.ffz-favorite:before { right: 2.5px; bottom: 2.5px }
.chat-menu.ffz-ui-popup .ffz-ui-menu-page .chat-menu-content.menu-side-padding { padding-left: 20px; padding-right: 20px; }
@@ -2015,6 +2019,8 @@ body.ffz-minimal-chat-input .ember-chat .chat-interface {
padding: 0;
}
+body.ffz-minimal-chat-input .ember-chat .chat-messages .chat-lines { padding-bottom: 0 }
+
body.ffz-minimal-chat-input .ember-chat .chat-interface .textarea-contain {
top: 0 !important;
margin: 0 !important;
@@ -2032,6 +2038,7 @@ body.ffz-minimal-chat-input .ember-chat .chat-interface .textarea-contain textar
/* Chat Pause */
.ember-chat .chat-interface .more-messages-indicator.ffz-freeze-indicator {
+ z-index: 10;
opacity: 1;
cursor: default;
pointer-events: none;
@@ -3551,6 +3558,11 @@ body.ffz-bttv #ffz-feed-tabs .tabs { margin-bottom: 0 }
padding-top: 5px;
}
+.ffz-baseline-emoticons .activity-body .emoticon.emoji,
+.ffz-baseline-emoticons .chat-line .emoticon.emoji {
+ padding-top: 0px;
+}
+
/* Settings Filtering */
@@ -3731,6 +3743,7 @@ div.metadata-box {
.cn-metabar__ffz[data-key="viewers"] svg { fill: #fc3636 }
.cn-metabar__ffz[data-key="viewers"] { color: #fc3636 }
+.ffz-dark .pl-button--hollow:hover,
.ffz-dark .button--hollow:hover,
.cn-hosting--bottom .button-hollow {
background-color: #2c2541;
@@ -4019,4 +4032,58 @@ body.ffz-sidebar-swap .app-main.theatre #main_col:not(.expandRight) #player[data
.dash-column {
margin-right: calc(1.5rem - 5px);
}
-}
\ No newline at end of file
+}
+
+
+/* ITAD */
+
+.button.button--large + .ffz-price-info > .itad-button {
+ font-size: 1.6rem;
+ line-height: 3.6rem;
+ padding: 0 1.2rem;
+}
+
+.itad-button {
+ background-color: #046eb2;
+ overflow: hidden;
+}
+
+.itad-button .button__num-block {
+ margin: 0 -3rem 0 0;
+ padding-right: 3rem !important;
+ display: inline-block;
+}
+
+.button.button--large + .ffz-price-info > .itad-button .button__num-block {
+ padding-right: 4.8rem !important;
+}
+
+.itad-button:focus,
+.itad-button:hover {
+ background-color: #1587cf;
+}
+
+.itad-button:focus { box-shadow: 0 0 6px 0 #5c99bf, inset 0 0 0 1px #9ec2d9 }
+
+.itad-balloon table {
+ width: 100%;
+ border-spacing: 0;
+}
+
+.itad-balloon th { border-bottom: 1px solid rgba(0,0,0,0.2) }
+.itad-balloon td { padding: 4px 0 0 }
+
+.itad-balloon span {
+ display: block;
+ border-top: 1px solid rgba(0,0,0,0.2);
+ margin-top: 5px;
+ padding-top: 5px;
+}
+
+.ffz-dark .itad-balloon th,
+.ffz-dark .itad-balloon span {
+ border-color: rgba(255,255,255,0.2);
+}
+
+.itad-balloon table th:not(:first-child),
+.itad-balloon table td:not(:first-child) { text-align: right }
\ No newline at end of file