From 630d2830ece83c212e42fa36538a328ecd294076 Mon Sep 17 00:00:00 2001
From: SirStendec
Date: Sun, 11 Jun 2017 13:30:37 -0400
Subject: [PATCH] The "Oh God Why Didn't I Commit Sooner" Edition
v3.5.494.
Added: Chat Filtering > Remove Messages from Moderators
Added: Recent Highlights
Added: Support for room-specific badges from the API.
Fixed: Custom bits badges. Lots of styling. Chat bugs. Dark theme issues. My Emoticons menu not rendering. Reset Player not rendering. Twitch5 extension compatibility. Logviewer messages and Name History. Bits UI breaking when you switch rooms. Player state when you reset the player.
Closes #173
Closes #169
Closes #164
---
changelog.html | 80 +++---
dark.css | 132 ++++++++++
old_changes.html | 105 ++++++++
src/ember/channel.js | 14 +-
src/ember/chat-input.js | 29 ++-
src/ember/chatview.js | 12 +
src/ember/layout.js | 17 +-
src/ember/line.js | 76 +++++-
src/ember/moderation-card.js | 2 +-
src/ember/player.js | 45 ++--
src/ember/room.js | 326 ++++++++++++++++++++++---
src/ember/sidebar.js | 3 +-
src/ext/api.js | 2 +-
src/ext/betterttv.js | 13 +
src/less/dark-clips.less | 23 ++
src/main.js | 2 +-
src/settings.js | 2 +-
src/styles/chat-padding.css | 1 +
src/styles/chat-separator-3d-inset.css | 1 +
src/styles/chat-separator-3d.css | 1 +
src/styles/chat-separator-wide.css | 1 +
src/styles/chat-separator.css | 1 +
src/tokenize.js | 16 +-
src/ui/channel_stats.js | 39 +--
src/ui/dark.js | 4 +
src/ui/following-count.js | 4 +-
src/ui/logviewer.js | 2 +-
src/ui/my_emotes.js | 125 ++++++++--
src/utils.js | 1 +
style.css | 157 ++++++++++--
30 files changed, 1049 insertions(+), 187 deletions(-)
diff --git a/changelog.html b/changelog.html
index ebe1ce05..004e070c 100644
--- a/changelog.html
+++ b/changelog.html
@@ -1,80 +1,62 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
diff --git a/dark.css b/dark.css
index bd1fe646..a3666aa2 100644
--- a/dark.css
+++ b/dark.css
@@ -534,6 +534,7 @@ body.ffz-dark:not([data-page="teams#show"]),
.ffz-dark .twitch_subwindow_container .card .buttons,
.ffz-dark .kraken-embed .card .buttons,
.ffz-dark .kraken-page .card .buttons,
+.ffz-dark .card--bordered,
.ffz-dark .card-vod-edit {
border-color: #474747;
}
@@ -619,6 +620,7 @@ body.ffz-dark:not([data-page="teams#show"]),
border-left-color: #6441a5;
}
+.ffz-dark .form__label,
.ffz-dark .form__input[type=checkbox] + label,
.ffz-dark .form__input[type=radio] + label,
.ffz-dark label,
@@ -946,6 +948,8 @@ body.ffz-dark:not([data-page="teams#show"]),
color: #ccc;
}
+.ffz-dark .section ul,
+.ffz-dark .section ul li,
.ffz-dark .subdash-feature-section,
.ffz-dark .subdash-feature-header__back,
.ffz-dark .subdash-feature-header,
@@ -971,6 +975,14 @@ body.ffz-dark:not([data-page="teams#show"]),
background-color: rgb(16,16,16);
}
+.ffz-dark fieldset {
+ border-color: transparent;
+}
+
+.ffz-dark .connect_items .connect-item-details,
+.ffz-dark .connect_items .connect-item-details-legal,
+.ffz-dark .connect_items,
+.ffz-dark .premium_setup_contain #turbo_setup,
.ffz-dark table.simple_table td,
.ffz-dark table.simple_table th,
.ffz-dark .cl-container .section-header,
@@ -1619,6 +1631,12 @@ body.ffz-dark:not([data-page="teams#show"]),
border: 1px solid;
}
+.ffz-dark .activity-card__reason {
+ background-color: #141414;
+ color: #ccc;
+ box-shadow: none;
+}
+
.ffz-dark .list-load-more,
.ffz-dark .activity-card {
border-color: #474747;
@@ -1646,20 +1664,100 @@ body.ffz-dark:not([data-page="teams#show"]),
box-shadow: none; /*inset 0 0 0 1px #474747;*/
}
+.ffz-dark .c-background { background: #101010 !important }
+
.ffz-dark .activity-create--focus {
background-color: #191919;
/*box-shadow: none; inset 0 0 0 1px #474747;*/
border-color: rgba(255,255,255,0.4) !important;
}
+.ffz-dark .c-text-alt { color: #999 !important }
+
.ffz-dark .activity-add-comment__textarea:before {
background: #1d1d1d;
border-left-color: #474747;
border-bottom-color: #474747;
}
+.ffz-dark .mod-dashboard__video-title,
+.ffz-dark .activity-card { color: #ccc }
+
.inherit-color { color: inherit !important }
+.ffz-dark .tw-button--icon-only figure svg {
+ fill: #a68cd4;
+}
+
+.ffz-dark .mod-comment {
+ background-color: #191919;
+ box-shadow: inset 0 0 0 1px #474747;
+}
+
+.ffz-dark .mod-comment__timestamp {
+ color: #a68cd4;
+ background-color: #222;
+}
+
+.ffz-dark .mod-comment__video a:active,
+.ffz-dark .mod-comment__video a:focus,
+.ffz-dark .mod-comment__video a:hover { background-color: #333 !important }
+
+.ffz-dark .mod-comment:active,
+.ffz-dark .mod-comment:focus,
+.ffz-dark .mod-comment:hover {
+ box-shadow: 0 2px 2px 0 rgba(255,255,255,.05), inset 0 0 0 1px #474747;
+}
+
+.ffz-dark .c-background-alt-2 {
+ background-color: #222 !important
+}
+
+.ffz-dark .automod-words__item {
+ border-color: #474747;
+ background-color: #111;
+}
+
+.ffz-dark .automod-words__item--selected {
+ background-color: #333;
+}
+
+.ffz-dark .automod-words__text { color: #ccc }
+
+.ffz-dark .automod-words__fade-mask {
+ background: none;
+}
+
+/* VOD Messages */
+
+.ffz-dark .vod-chat {
+ color: #ccc;
+ background-color: #191919;
+}
+
+.ffz-dark .vod-chat__header {
+ box-shadow: inset 0 -1px 0 0 #474747;
+}
+
+.ffz-dark .vod-message.vod-message--focused .vod-message__reply,
+.ffz-dark .vod-message:hover .vod-message__reply,
+.ffz-dark .vod-message__reply {
+ box-shadow: inset 3px 0 0 0 #474747;
+}
+
+.ffz-dark .vod-message__reply-button {
+ color: #a68cd4;
+}
+
+.ffz-dark .vod-chat__input {
+ background-color: #191919;
+ box-shadow: inset 0 1px 0 0 #474747;
+}
+
+.ffz-dark .vod-message.vod-message--focused,
+.ffz-dark .vod-message:hover {
+ background-color: #333;
+}
/* Search Panel */
@@ -1791,6 +1889,15 @@ body.ffz-dark:not([data-page="teams#show"]),
border-color: rgba(255,255,255,0.2);
}
+.ffz-dark .subscription-modal__sub-tabs input:checked+.subscription-modal__sub-tabs-label {
+ color: #ccc;
+ box-shadow: 0 -2px 0 #a68ed2 inset, 0 4px 6px -4px #a68cd4;
+}
+
+.ffz-dark .subscription-modal__sub-tabs-label {
+ color: #a68cd4;
+}
+
.ffz-dark .balloon .filter-bar__balloon-link--active {
color: #fff !important;
background-color: #6441a5 !important;
@@ -1814,6 +1921,10 @@ body.ffz-dark:not([data-page="teams#show"]),
border-color: rgba(255,255,255,0.2);
}
+.ffz-dark .dash-widget-watchparty-card:hover {
+ background-color: rgba(255,255,255,0.1);
+}
+
/* Notification Center */
@@ -1918,6 +2029,7 @@ body.ffz-dark:not([data-page="teams#show"]),
background-color: #161616;
}
+.ffz-dark .dash-widget-watchparty-card__gripper,
.ffz-dark .playlist-editor-card__gripper {
background-color: #242424;
box-shadow: -8px 0 5px -5px #202020;
@@ -1946,6 +2058,8 @@ body.ffz-dark:not([data-page="teams#show"]),
border-color: #474747;
}
+.ffz-dark .fp-carousel__title,
+.ffz-dark .fp-carousel__desc p,
.ffz-dark .fp-carousel__name,
.ffz-dark .fp-side__header { color: #c3c3c3 }
@@ -1972,7 +2086,25 @@ body.ffz-dark:not([data-page="teams#show"]),
fill: #ccc;
}
+.ffz-dark .activity--not-included { background-color: #202020; }
+
+.ffz-dark .activity--level-0 { background-color: rgba(100,65,164,.1) }
+.ffz-dark .activity--level-1 { background-color: rgba(100,65,164,.25) }
+.ffz-dark .activity--level-2 { background-color: rgba(100,65,164,.4) }
+.ffz-dark .activity--level-3 { background-color: rgba(100,65,164,.55) }
+.ffz-dark .activity--level-4 { background-color: rgba(100,65,164,.7) }
+.ffz-dark .activity--level-5 { background-color: rgba(100,65,164,.85) }
+.ffz-dark .activity--level-6 { background-color: rgba(100,65,164,1) }
+
.ffz-dark .inventory-item__image {
background-color: #191919;
border-color: #474747;
+}
+
+.ffz-dark .border-r {
+ border-color: #474747;
+}
+
+.ffz-dark .bg--grey {
+ background-color: #242424;
}
\ No newline at end of file
diff --git a/old_changes.html b/old_changes.html
index ef38761f..50857771 100644
--- a/old_changes.html
+++ b/old_changes.html
@@ -1,3 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Default: 50",
+ this.settings.recent_highlight_count,
+ 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 = 50;
+
+ new_val = Math.max(1, new_val);
+
+ f.settings.set("recent_highlight_count", new_val);
+ });
+ },
+
+ on_update: function(val) {
+ for(var room_id in this.rooms) {
+ var r = this.rooms[room_id] && this.rooms[room_id].room,
+ rh = r && r.get('ffz_recent_highlights');
+
+ if ( rh && rh.length > val )
+ r.set('ffz_recent_highlights', rh.splice(Math.max(0, rh.length - val), rh.length));
+ }
+
+ this._roomv && this._roomv.ffzUpdateRecent();
+ }
+}
+
+
FFZ.settings_info.emoji_scale = {
type: "select",
options: {
@@ -676,9 +742,9 @@ FFZ.settings_info.chat_font_size = {
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; }";
+ css = ".ffz-recent-messages .chat-line,.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; }";
+ css += ".ffz-recent-messages .chat-line .mod-icons,.pinned-cheers .chat-line,.ember-chat .chat-messages .chat-line .mod-icons, .ember-chat .chat-messages .chat-line .badges { padding-top: " + pd + "px; }";
}
utils.update_css(this._chat_style, "chat_font_size", css);
@@ -730,7 +796,7 @@ FFZ.settings_info.chat_ts_size = {
css = "";
else {
var lh = Math.max(20, Math.round((20/12)*val), Math.round((20/12)*this.settings.chat_font_size));
- css = ".ember-chat .chat-messages .timestamp { font-size: " + val + "px !important; line-height: " + lh + "px !important; }";
+ css = ".ffz-recent-messages .timestamp,.ember-chat .chat-messages .timestamp { font-size: " + val + "px !important; line-height: " + lh + "px !important; }";
}
utils.update_css(this._chat_style, "chat_ts_font_size", css);
diff --git a/src/ember/moderation-card.js b/src/ember/moderation-card.js
index ddb2ba3a..3205e8ea 100644
--- a/src/ember/moderation-card.js
+++ b/src/ember/moderation-card.js
@@ -883,7 +883,7 @@ FFZ.prototype.modify_moderation_card = function(component) {
// If we're viewing the chat history, update it.
var el = this.get('element'),
container = el && el.querySelector('.ffz-tab-container'),
- history = container && container.querySelector('.chat-history.lv-history');
+ history = container && container.querySelector('.ffz-tab-container[data-page="history"] .chat-history.lv-history');
if ( history ) {
var was_at_bottom = history.scrollTop >= (history.scrollHeight - history.clientHeight),
diff --git a/src/ember/player.js b/src/ember/player.js
index 06126872..412f9623 100644
--- a/src/ember/player.js
+++ b/src/ember/player.js
@@ -30,10 +30,8 @@ FFZ.settings_info.player_stats = {
help: "Display your current stream latency (how far behind the broadcast you are) under the player, with a few useful statistics in a tooltip.",
on_update: function(val) {
- if ( ! this._cindex )
- return;
-
- this._cindex.ffzUpdateMetadata('player_stats');
+ if ( this._cindex )
+ this._cindex.ffzUpdateMetadata('player_stats');
}
};
@@ -199,12 +197,19 @@ FFZ.prototype.modify_twitch_player = function(player) {
},
ffzRecreatePlayer: function() {
- var player = this.get('player'),
- theatre = player && player.getTheatre();
+ var t = this,
+ player = this.get('player'),
+ theatre, fullscreen, had_player = false;
// Tell the player to destroy itself.
- if ( player )
+ if ( player ) {
+ had_player = true;
+ fullscreen = player.fullscreen;
+ theatre = player.theatre;
+ player.fullscreen = false;
+ player.theatre = false;
player.destroy();
+ }
// Break down everything left over from that player.
this.$('#player').html('');
@@ -213,7 +218,16 @@ FFZ.prototype.modify_twitch_player = function(player) {
this.set('ffz_post_player', false);
// Now, let Twitch create a new player as usual.
- Ember.run.next(this.didInsertElement.bind(this));
+ Ember.run.next(function() {
+ t.didInsertElement();
+ had_player && setTimeout(function() {
+ var player = t.get('player');
+ if ( player ) {
+ //player.fullscreen = fullscreen;
+ player.theatre = theatre;
+ }
+ })
+ });
},
/*ffzUpdatePlayerPaused: function() {
@@ -269,17 +283,18 @@ FFZ.prototype.modify_twitch_player = function(player) {
// Add an option to the menu to recreate the player.
var t = this,
- el = this.$('.player-menu .player-menu__item--stats')[0],
+ el = this.$('.player-buttons-right #js-settings')[0],
container = el && el.parentElement;
- if ( el && ! container.querySelector('.js-player-reset') ) {
- var btn_link = utils.createElement('a', 'player-text-link js-player-reset', 'Reset Player'),
- btn = utils.createElement('p', 'player-menu__item player-menu__item--reset pl-small', btn_link);
+ if ( el && ! container.querySelector('.ffz-player-reset') ) {
+ var btn = utils.createElement('button', 'player-button player-button--reset ffz-player-reset');
+ btn.type = 'button';
- btn_link.tabindex = '-1';
- btn_link.href = '#';
+ btn.innerHTML = '' +
+ constants.CLOSE;
- btn_link.addEventListener('click', function(e) {
+ jQuery(btn).on('dblclick', function(e) {
+ //btn.addEventListener('click', function(e) {
t.ffzRecreatePlayer();
e.preventDefault();
return false;
diff --git a/src/ember/room.js b/src/ember/room.js
index c02b5572..43d6fd55 100644
--- a/src/ember/room.js
+++ b/src/ember/room.js
@@ -178,6 +178,28 @@ FFZ.prototype.setup_room = function() {
}
+ var ChannelSubs = utils.ember_lookup('service:channel-subscriptions');
+ if ( ChannelSubs ) {
+ this.log("Hooking the Ember Channel Subscriptions service.");
+ ChannelSubs.reopen({
+ populateSubNotificationTokens: function() {
+ var Chat = utils.ember_lookup('controller:chat'),
+ tokens = Chat && Chat.get('currentRoom.roomProperties.available_chat_notification_tokens');
+
+ return this._super(tokens);
+ },
+
+ _reloadSubNotificationToken: function(e) {
+ var t = this;
+ return this.get("api").request("get", "/api/channels/" + e + "/chat_properties").then(function(e) {
+ var room = f.rooms && f.rooms[e] && f.rooms[e].room;
+ room && room.set('roomProperties.available_chat_notification_tokens', e.available_chat_notification_tokens);
+ t.isDestroyed || t.populateSubNotificationTokens(e.available_chat_notification_tokens)
+ })
+ },
+ });
+ }
+
this.update_views('component:chat/chat-room', this.modify_room_component);
this.update_views('component:chat/chat-interface', this.modify_chat_interface);
@@ -657,7 +679,8 @@ FFZ.HoverPause = {
FFZ.prototype.modify_room_component = function(component) {
var f = this,
- PinnedCheers = utils.ember_lookup('service:bits-pinned-cheers');
+ PinnedCheers = utils.ember_lookup('service:bits-pinned-cheers'),
+ ChannelSubs = utils.ember_lookup('service:channel-subscriptions');
utils.ember_reopen_view(component, _.extend({
ffz_init: function() {
@@ -676,9 +699,18 @@ FFZ.prototype.modify_room_component = function(component) {
this.ffzUpdateStatus();
}
- var actions = this._actions || {},
+ var t = this,
+ actions = this._actions || {},
orig_show = actions.showModOverlay;
+ actions.accommodatePinnedMessage = function(e) {
+ var el = t.get('element'),
+ chat = el.querySelector('.js-chat-messages');
+
+ if ( chat )
+ chat.dataset.pinned_height = e;
+ };
+
actions.showModOverlay = function(e) {
var Channel = utils.ember_resolve('model:deprecated-channel'),
chan = Channel && Channel.find && Channel.find({id: e.sender});
@@ -709,6 +741,8 @@ FFZ.prototype.modify_room_component = function(component) {
isModeratorOrHigher: this.get("room.isModeratorOrHigher")
});
}
+
+ this.ffzUpdateRecent();
},
ffz_destroy: function() {
@@ -719,18 +753,181 @@ FFZ.prototype.modify_room_component = function(component) {
this.ffzRemoveKeyHook();
},
+
+ ffzUpdateRecent: function() {
+ var t = this,
+ el = this.get('element'),
+ container = this.get('ffz_recent_el'),
+ con_count = this.get('ffz_recent_count_el'),
+ should_show = f.settings.recent_highlights && ! f.has_bttv;
+
+ if ( ! el )
+ return;
+
+ if ( ! container ) {
+ if ( ! should_show )
+ return;
+
+ container = utils.createElement('ul', 'chat-history');
+ var expander = utils.createElement('div', 'ffz-recent-expando', 'Recent Highlights'),
+ big_el = utils.createElement('div', 'ffz-recent-messages', expander),
+ btn_handle = utils.createElement('span', 'ffz-handle ffz-close-button'),
+ super_parent = document.body.querySelector('.app-main');
+
+ con_count = expander.querySelector('.pill');
+ container.classList.toggle('dark', f.settings.dark_twitch);
+ expander.insertBefore(btn_handle, expander.firstChild);
+ container.dataset.docked = true;
+
+ big_el.appendChild(container);
+ el.appendChild(big_el);
+ el.classList.add('ffz-has-recent-messages');
+
+ this.set('ffz_recent_el', container);
+ this.set('ffz_recent_count_el', con_count);
+
+ expander.addEventListener('mousemove', function(e) {
+ con_count.textContent = '';
+ t.set('room.ffz_recent_highlights_unread', 0);
+ });
+
+ btn_handle.addEventListener('click', function(e) {
+ if ( ! big_el.classList.contains('ui-moved') || ! e.button === 0 )
+ return;
+
+ big_el.style.top = 0;
+ big_el.style.left = 0;
+ big_el.classList.remove('ui-moved');
+ big_el.parentElement.removeChild(big_el);
+ el.appendChild(big_el);
+ el.classList.add('ffz-has-recent-messages');
+ container.dataset.docked = true;
+ });
+
+ var st;
+ jQuery(big_el).draggable({
+ handle: expander,
+ start: function(e) {
+ st = container.scrollTop;
+ big_el.classList.add('ui-moved');
+ container.dataset.docked = false;
+ el.classList.remove('ffz-has-recent-messages');
+ },
+
+ stop: function(e) {
+ if ( big_el.parentElement !== super_parent ) {
+ var rect = big_el.getBoundingClientRect(),
+ pr = super_parent.getBoundingClientRect();
+
+ big_el.parentElement.removeChild(big_el);
+ super_parent.appendChild(big_el);
+
+ big_el.style.top = (rect.top - pr.top) + "px";
+ big_el.style.left = (rect.left - pr.left) + "px";
+ }
+
+ container.scrollTop = st;
+ }
+ });
+
+ jQuery(container).on('click', '.chat-line', function(e) {
+ if ( ! e.target || e.button !== 0 )
+ return;
+
+ var jq = jQuery(e.target),
+ cl = e.target.classList,
+ line = cl.contains('chat-line') ? e.target : jq.parents('.chat-line')[0],
+ room_id = line && line.dataset.room,
+ room = room_id && f.rooms[room_id] && f.rooms[room_id].room,
+ from = line && line.dataset.sender,
+ msg_id = line && line.dataset.id;
+
+ if ( cl.contains('deleted-word') ) {
+ jq.trigger('mouseout');
+ e.target.outerHTML = e.target.dataset.text;
+
+ } else if ( cl.contains('deleted-link') )
+ return f._deleted_link_click.call(e.target, e);
+
+ else if ( cl.contains('badge') ) {
+ if ( cl.contains('click_action') ) {
+ var badge = f.badges && f.badges[e.target.getAttribute('data-badge-id')];
+ if ( badge.click_action )
+ badge.click_action.call(f, this.get('msgObject'), e);
+
+ } else if ( cl.contains('click_url') )
+ window.open(e.target.dataset.url, "_blank");
+
+ else if ( cl.contains('turbo') )
+ window.open("/products/turbo?ref=chat_badge", "_blank");
+
+ else if ( cl.contains('subscriber') )
+ window.open("/" + room_id + "/subscribe?ref=in_chat_subscriber_link");
+
+ } else if ( f._click_emote(e.target, e) )
+ return;
+
+ else if ( (f.settings.clickable_mentions && cl.contains('user-token')) || cl.contains('from') || e.target.parentElement.classList.contains('from') ) {
+ var target = cl.contains('user-token') ? e.target.dataset.user : from;
+ if ( ! target )
+ return;
+
+ var bounds = line && line.getBoundingClientRect() || document.body.getBoundingClientRect(),
+ x = 0, right;
+
+ if ( bounds.left > 400 )
+ right = bounds.left - 40;
+
+ f._roomv.actions.showModOverlay.call(f._roomv, {
+ left: bounds.left,
+ right: right,
+ top: bounds.top + bounds.height,
+ real_top: bounds.top,
+ sender: target
+ });
+
+ }
+ });
+
+ } else if ( ! should_show ) {
+ jQuery(container.parentElement).remove();
+ this.set('ffz_recent_el', null);
+ this.set('ffz_recent_count_el', null);
+ el.classList.remove('ffz-has-recent-messages');
+ return;
+ }
+
+ var was_at_bottom = container.scrollTop >= (container.scrollHeight - container.clientHeight);
+ container.innerHTML = '';
+ con_count.textContent = container.dataset.docked ? utils.format_unread(this.get('room.ffz_recent_highlights_unread') || 0) : '';
+
+ var messages = this.get('room.ffz_recent_highlights') || [];
+ for(var i=0; i < messages.length; i++)
+ container.appendChild(f._build_mod_card_history(messages[i], null, true));
+
+ if ( was_at_bottom )
+ container.scrollTop = container.scrollHeight;
+
+ }.observes('room'),
+
+
ffzUpdateBits: function() {
var t = this,
- channel = this.get('room.channel');
- if ( ! channel )
+ channel = this.get('room.channel'),
+ bits_room = this.get('bitsRoom');
+ if ( ! channel || ! bits_room )
return;
PinnedCheers && PinnedCheers.dismissLocalMessage();
if ( ! channel.get('isLoaded') )
- channel.load().then(function() { t._initializeBits(channel) })
- else
+ channel.load().then(function() { bits_room.reset(); t._initializeBits(channel) })
+ else {
+ bits_room.reset();
this._initializeBits(channel);
+ }
+
+ ChannelSubs && ChannelSubs.populateSubNotificationTokens(this.get('room.roomProperties.available_chat_notification_tokens'));
}.observes('room'),
@@ -1130,7 +1327,7 @@ FFZ.prototype._load_room_json = function(room_id, callback, data) {
var model = this.rooms[room_id] = this.rooms[room_id] || {};
for(var key in data)
- if ( key !== 'users' && key !== 'room' && data.hasOwnProperty(key) )
+ if ( key !== 'user_badges' && key !== 'users' && key !== 'room' && data.hasOwnProperty(key) )
model[key] = data[key];
// Merge the user data.
@@ -1144,6 +1341,21 @@ FFZ.prototype._load_room_json = function(room_id, callback, data) {
}
}
+ // Merge badge data
+ for(var badge_id in data.user_badges) {
+ var badge = this.badges[badge_id];
+ if ( ! badge )
+ continue;
+
+ for(var l=data.user_badges[badge_id], i=0, j=l.length; i < j; i++) {
+ var user_id = l[i],
+ user = model.users[user_id] = model.users[user_id] || {},
+ badges = user.badges = user.badges || {};
+
+ badges[badge.slot] = {id: badge_id};
+ }
+ }
+
// Preserve the pointer to the Room instance.
/*if ( this.rooms[room_id] )
data.room = this.rooms[room_id].room;
@@ -1192,6 +1404,8 @@ FFZ.prototype._modify_room = function(room) {
ffz_banned: false,
mru_list: [],
+ ffz_recent_highlights: [],
+ ffz_recent_highlights_unread: 0,
ffzUpdateBadges: function() {
if ( this.get('isGroupRoom') )
@@ -1299,7 +1513,7 @@ FFZ.prototype._modify_room = function(room) {
try {
f.add_room(this.id, this);
- this.set("ffz_chatters", {});
+ this.set("ffz_chatters", []);
this.set("ffz_ids", this.get('ffz_ids') || {});
this.set("ffz_last_notices", this.get('ffz_last_notices') || {});
} catch(err) {
@@ -1789,7 +2003,10 @@ FFZ.prototype._modify_room = function(room) {
ffzPushMessages: function(messages) {
var new_messages = [],
- new_unread = 0;
+ new_unread = 0,
+
+ highlight_messages = [],
+ highlight_unread = 0;
for(var i=0; i < messages.length; i++) {
var msg = messages[i];
@@ -1797,8 +2014,11 @@ FFZ.prototype._modify_room = function(room) {
new_messages.push(msg);
if ( ! (msg.tags && msg.tags.historical) && msg.style !== "admin" && msg.style !== "whisper" ) {
- if ( msg.ffz_has_mention )
+ if ( msg.ffz_has_mention ) {
this.ffz_last_mention = Date.now();
+ highlight_messages.push(msg);
+ highlight_unread++;
+ }
new_unread++;
}
@@ -1867,6 +2087,39 @@ FFZ.prototype._modify_room = function(room) {
this.incrementProperty("unreadCount", new_unread);
this.ffz_last_activity = Date.now();
}
+
+ if ( f.settings.recent_highlights && highlight_unread ) {
+ var old_highlights = this.get('ffz_recent_highlights') || [],
+ raw_remove = old_highlights.length + highlight_messages.length > f.settings.recent_highlight_count ?
+ Math.max(0, old_highlights.length - f.settings.recent_highlight_count) + highlight_messages.length : 0,
+
+ to_remove = raw_remove % 2,
+ trimmed = old_highlights.slice(to_remove, old_highlights.length).concat(highlight_messages),
+ el = f._roomv && f._roomv.get('ffz_recent_el');
+
+ this.set('ffz_recent_highlights', trimmed);
+ this.incrementProperty('ffz_recent_highlights_unread', highlight_unread);
+
+ if ( el && f._roomv.get('room') === this ) {
+ var was_at_bottom = el.scrollTop >= (el.scrollHeight - el.clientHeight);
+
+ while( el.childElementCount && to_remove-- )
+ el.removeChild(el.firstElementChild);
+
+ for(var i=0; i < highlight_messages.length; i++)
+ el.appendChild(f._build_mod_card_history(highlight_messages[i], null, true));
+
+ if ( was_at_bottom )
+ el.scrollTop = el.scrollHeight;
+
+ if ( el.dataset.docked ) {
+ el = f._roomv.get('ffz_recent_count_el');
+ if ( el )
+ el.textContent = utils.format_unread(this.get('ffz_recent_highlights_unread'));
+ }
+
+ }
+ }
},
ffzSchedulePendingFlush: function(now) {
@@ -2023,7 +2276,7 @@ FFZ.prototype._modify_room = function(room) {
ffzProcessMessage: function(msg) {
if ( msg ) {
var notice_type = msg.tags && msg.tags['msg-id'],
- is_resub = notice_type === 'resub',
+ is_resub = notice_type === 'resub' || notice_type === 'sub',
room_id = this.get('id'),
msg_id = msg.tags && msg.tags.id;
@@ -2177,10 +2430,6 @@ FFZ.prototype._modify_room = function(room) {
f.api_trigger('room-message', msg);
- // Also update chatters.
- if ( ! is_whisper && this.chatters && ! this.chatters[msg.from] && msg.from !== 'twitchnotify' && msg.from !== 'jtv' )
- this.ffzUpdateChatters(msg.from);
-
// We're past the last return, so store the message
// now that we know we're keeping it.
if ( msg_id ) {
@@ -2195,8 +2444,8 @@ FFZ.prototype._modify_room = function(room) {
}
// Report this message to the dashboard.
- if ( window !== window.parent && parent.postMessage && msg.from && msg.from !== "jtv" && msg.from !== "twitchnotify" )
- parent.postMessage({from_ffz: true, command: 'chat_message', data: {from: msg.from, room: msg.room}}, "*"); //location.protocol + "//www.twitch.tv/");
+ if ( msg.from && msg.from !== "jtv" && msg.from !== "twitchnotify" )
+ this.ffzSafePM({from_ffz: true, command: 'chat_message', data: {from: msg.from, room: msg.room}}, "*"); //location.protocol + "//www.twitch.tv/");
// Flagging for review.
if ( msg.tags && msg.tags.risk === "high" )
@@ -2330,8 +2579,11 @@ FFZ.prototype._modify_room = function(room) {
}.observes('unreadCount'),
ffzInitChatterCount: function() {
- if ( ! this.tmiRoom )
+ if ( ! this.tmiRoom || ! f.settings.chatter_count ) {
+ this.set("ffz_chatters", []);
+ this.ffzUpdateChatters();
return;
+ }
if ( this._ffz_chatter_timer ) {
clearTimeout(this._ffz_chatter_timer);
@@ -2340,26 +2592,27 @@ FFZ.prototype._modify_room = function(room) {
var room = this;
this.tmiRoom.list().done(function(data) {
- var chatters = {};
+ var chatters = [];
data = data.data.chatters;
if ( data && data.admins )
for(var i=0; i < data.admins.length; i++)
- chatters[data.admins[i]] = true;
+ chatters.push(data.admins[i]);
if ( data && data.global_mods )
for(var i=0; i < data.global_mods.length; i++)
- chatters[data.global_mods[i]] = true;
+ chatters.push(data.global_mods[i]);
if ( data && data.moderators )
for(var i=0; i < data.moderators.length; i++)
- chatters[data.moderators[i]] = true;
+ chatters.push(data.moderators[i]);
if ( data && data.staff )
for(var i=0; i < data.staff.length; i++)
- chatters[data.staff[i]] = true;
+ chatters.push(data.staff[i]);
if ( data && data.viewers )
for(var i=0; i < data.viewers.length; i++)
- chatters[data.viewers[i]] = true;
+ chatters.push(data.viewers[i]);
room.set("ffz_chatters", chatters);
room.ffzUpdateChatters();
+
}).always(function() {
room._ffz_chatter_timer = setTimeout(room.ffzInitChatterCount.bind(room), 300000);
});
@@ -2367,22 +2620,31 @@ FFZ.prototype._modify_room = function(room) {
ffzUpdateChatters: function(add, remove) {
- var chatters = this.get("ffz_chatters") || {};
- if ( add )
- chatters[add] = true;
- if ( remove && chatters[remove] )
- delete chatters[remove];
-
if ( ! f.settings.chatter_count )
return;
+ var chatters = this.get("ffz_chatters") || [];
+ if ( add && chatters.indexOf(add) === -1 )
+ chatters.push(add);
+
+ if ( remove ) {
+ var ind = chatters.indexOf(remove);
+ if ( ind !== -1 )
+ chatters.splice(ind, 1);
+ }
+
if ( f._cindex )
f._cindex.ffzUpdateMetadata('chatters');
- if ( window !== window.parent && parent.postMessage )
- parent.postMessage({from_ffz: true, command: 'chatter_count', data: {room: this.get('id'), chatters: Object.keys(this.get('ffz_chatters') || {}).length}}, "*"); //location.protocol + "//www.twitch.tv/");
+ this.ffzSafePM({from_ffz: true, command: 'chatter_count', data: {room: this.get('id'), chatters: (this.get('ffz_chatters') || []).length}}, "*"); //location.protocol + "//www.twitch.tv/");
},
+ ffzSafePM: function(message, origin) {
+ try {
+ if ( window !== window.parent && parent.postMessage )
+ return parent.postMessage(message, origin);
+ } catch(err) { }
+ },
ffzPatchTMI: function() {
var tmi = this.get('tmiRoom'),
diff --git a/src/ember/sidebar.js b/src/ember/sidebar.js
index 91579d54..3c71e971 100644
--- a/src/ember/sidebar.js
+++ b/src/ember/sidebar.js
@@ -382,7 +382,7 @@ FFZ.prototype.modify_social_followed_channel = function(component) {
ffz_init: function() {
var t = this,
el = this.get('element'),
- card = jQuery('.sc-card', el),
+ card = jQuery('.js-sc-card', el),
data = card && card.data('tipsy');
if ( ! data || ! data.options )
@@ -418,6 +418,7 @@ FFZ.prototype.modify_social_followed_channel = function(component) {
'' + constants.LIVE + ' ' + utils.number_commas(data.stream.viewers) + '' +
'' + utils.sanitize(channel.display_name || channel.name) + '
' +
'' +
+ (data.stream.stream_type === 'watch_party' ? 'Vodcast ' : '') +
(channel.game === 'Creative' ?
'Being Creative' :
(channel.game ?
diff --git a/src/ext/api.js b/src/ext/api.js
index a00308f8..0ca4dcdf 100644
--- a/src/ext/api.js
+++ b/src/ext/api.js
@@ -104,7 +104,7 @@ API.prototype.log = function(msg, data, to_json, log_json) {
API.prototype.error = function(msg, error, to_json, log_json) {
- this.ffz.error('Ext #' + this.id + ' (' + this.name_key + '): ' + msg, data, to_json, log_json);
+ this.ffz.error('Ext #' + this.id + ' (' + this.name_key + '): ' + msg, error, to_json, log_json);
}
diff --git a/src/ext/betterttv.js b/src/ext/betterttv.js
index a70f406e..334749c6 100644
--- a/src/ext/betterttv.js
+++ b/src/ext/betterttv.js
@@ -96,6 +96,18 @@ FFZ.prototype.setup_bttv_7 = function(delay) {
}
+ /* Update the chat input to not use FFZ's input handling.
+ if ( this._inputv ) {
+ var t = this._inputv.$("textarea");
+ t.off("keyup");
+ t.off("keydown");
+ t.off("keypress");
+ t.on("keyup", this._inputv._onKeyUp.bind(this._inputv));
+ t.on("keydown", this._inputv._onKeyDown.bind(this._inputv));
+ }//*/
+
+
+
// Hook into BTTV's dark mode.
cl.add('ffz-bttv');
cl.toggle('ffz-bttv-dark', settings.get('darkenedMode'));
@@ -105,6 +117,7 @@ FFZ.prototype.setup_bttv_7 = function(delay) {
});
this.update_ui_link();
+ this._roomv && this._roomv.ffzUpdateRecent();
this.api_trigger('bttv-initialized', 7);
}
diff --git a/src/less/dark-clips.less b/src/less/dark-clips.less
index 13b01c99..416574e4 100644
--- a/src/less/dark-clips.less
+++ b/src/less/dark-clips.less
@@ -41,6 +41,29 @@
.svg-logo_twitch, .clips-nav__logo { fill: white }
+ .nav-banner {
+ background-color: lighten(@nav-bg-color, 10%);
+ }
+
+
+ // Chat
+
+ .clip-chat-message {
+ color: #ccc;
+ }
+
+ .view-clip__main--darker {
+ background-color: darken(@nav-bg-color, 2%);
+ }
+
+ .view-clip__smallTitle {
+ color: @fg-color;
+
+ & > div {
+ background-color: @nav-bg-color;
+ border-bottom: lighten(@nav-bg-color, 10%);
+ }
+ }
// Content Meta
.nv-clip-content {
diff --git a/src/main.js b/src/main.js
index a9ec608c..79f55a0d 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: 480,
+ major: 3, minor: 5, revision: 494,
toString: function() {
return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || "");
}
diff --git a/src/settings.js b/src/settings.js
index 02111951..936834cd 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -240,7 +240,7 @@ var is_android = navigator.userAgent.indexOf('Android') !== -1,
search_input.placeholder = 'Search for Settings';
search_input.type = 'text';
- filtered_cont.style.maxHeight = (parseInt(container.style.maxHeight) - 51) + 'px';
+ filtered_cont.style.maxHeight = (parseInt(container.style.maxHeight) - 53) + 'px';
search_cont.appendChild(search_input);
container.appendChild(filtered_cont);
diff --git a/src/styles/chat-padding.css b/src/styles/chat-padding.css
index af0b642b..67471bc1 100644
--- a/src/styles/chat-padding.css
+++ b/src/styles/chat-padding.css
@@ -1,4 +1,5 @@
/* Chat Line Padding */
+.chat-history .chat-line,
.ember-chat .chat-messages .chat-line,
.ember-chat .chat-messages .chat-line.admin,
diff --git a/src/styles/chat-separator-3d-inset.css b/src/styles/chat-separator-3d-inset.css
index 87fd0a15..79209588 100644
--- a/src/styles/chat-separator-3d-inset.css
+++ b/src/styles/chat-separator-3d-inset.css
@@ -5,6 +5,7 @@
border-bottom-color: rgba(255,255,255, 0.5);
}
+.chat-history .chat-line,
.ember-chat .chat-messages .chat-line,
.ember-chat .chat-messages .chat-line.admin { padding-top: 2px }
diff --git a/src/styles/chat-separator-3d.css b/src/styles/chat-separator-3d.css
index ad999c4e..75c14e98 100644
--- a/src/styles/chat-separator-3d.css
+++ b/src/styles/chat-separator-3d.css
@@ -4,6 +4,7 @@
border-top: 1px solid rgba(255,255,255, 0.5);
}
+.chat-history .chat-line,
.ember-chat .chat-messages .chat-line,
.ember-chat .chat-messages .chat-line.admin { padding-top: 2px }
diff --git a/src/styles/chat-separator-wide.css b/src/styles/chat-separator-wide.css
index 2ac8eead..49487365 100644
--- a/src/styles/chat-separator-wide.css
+++ b/src/styles/chat-separator-wide.css
@@ -4,6 +4,7 @@
border-top: 1px solid #aaa;
}
+.chat-history .chat-line,
.ember-chat .chat-messages .chat-line,
.ember-chat .chat-messages .chat-line.admin { padding-top: 2px }
diff --git a/src/styles/chat-separator.css b/src/styles/chat-separator.css
index d24f5ea3..dc76285d 100644
--- a/src/styles/chat-separator.css
+++ b/src/styles/chat-separator.css
@@ -5,6 +5,7 @@
border-bottom: 1px solid #aaa;
}
+.chat-history .chat-line,
.ember-chat .chat-messages .chat-line,
.ember-chat .chat-messages .chat-line.admin { padding-bottom: 2px }
diff --git a/src/tokenize.js b/src/tokenize.js
index 1cf18bfb..af966f12 100644
--- a/src/tokenize.js
+++ b/src/tokenize.js
@@ -798,7 +798,7 @@ FFZ.prototype.tokenize_chat_line = function(msgObject, prevent_notification, del
// Mentions!
if ( ! from_me ) {
tokens = this.tokenize_mentions(tokens);
- var st = this.settings.remove_filtered;
+ var st = (mod_or_higher && !this.settings.remove_filtered_mod) ? 0 : this.settings.remove_filtered;
for(var i=0; i < tokens.length; i++) {
var token = tokens[i],
@@ -1076,14 +1076,16 @@ FFZ.prototype.render_token = function(render_links, warn_links, render_bits, tok
video_info = VIDEO_URL.exec(href);
if ( clip_info ) {
- var clips = utils.ember_lookup('service:clips');
- clips && clips.getClipInfo(clip_info[1]).then(function(data) {
+ var clips = utils.ember_lookup('service:store');
+ clips && clips.findRecord && clips.findRecord('clip', clip_info[1]).then(function(data) {
+ //clips && clips.getClipInfo(clip_info[1]).then(function(data) {
+ data &&
success(true, {
- image: data.previewImage,
+ image: data.get('scaledPreviewUrl'),
image_iframe: false,
- html: '' + utils.sanitize(data.title) + '' +
- 'Channel: ' + utils.sanitize(data.broadcasterDisplayName) +
- '
Game: ' + utils.sanitize(data.game)
+ html: '' + utils.sanitize(data.get('title')) + '' +
+ 'Channel: ' + utils.sanitize(data.get('broadcasterDisplayName')) +
+ '
Game: ' + utils.sanitize(data.get('game'))
});
});
diff --git a/src/ui/channel_stats.js b/src/ui/channel_stats.js
index 5d67f525..9f0e943e 100644
--- a/src/ui/channel_stats.js
+++ b/src/ui/channel_stats.js
@@ -90,30 +90,39 @@ metadata.player_stats = {
stats = player.getVideoInfo();
} catch(err) { }
+ // Check for server offset.
+ var delayed = undefined;
+ if ( this._ws_open ) {
+ var offset = this._ws_server_offset;
+ if ( isNaN(offset) || ! isFinite(offset) )
+ this.ws_ping();
+ else
+ delayed = offset > 5000;
+ }
+
var delay = stats && Math.round(stats.hls_latency_broadcaster / 10) / 100;
- return [stats, delay, delay > 180, player_cont];
+ return [stats, delay, delay > 180, player_cont, delayed];
},
order: 3,
host_order: 102,
static_label: constants.GRAPH,
- label: function(stats, delay, is_old) {
- if ( ! this.settings.player_stats || ! stats || ! stats.hls_latency_broadcaster )
+ label: function(stats, delay, is_old, player_cont, delayed) {
+ if ( ! this.settings.player_stats || ! delay )
return null;
+ delayed = delayed ? '(!) ' : '';
+
if ( is_old )
- return utils.time_to_string(Math.floor(delay), true, delay > 172800) + ' old'
- else {
- delay = delay.toString();
- var ind = delay.indexOf('.');
- return delay + (ind === -1 ? '.00' : (ind >= delay.length - 2 ? '0' : '')) + 's';
- }
+ return delayed + utils.time_to_string(Math.floor(delay), true, delay > 172800) + ' old'
+ else
+ return delayed + delay.toFixed(2) + 's';
},
color: function(stats, delay, is_old) {
var setting = this.settings.player_stats;
- if ( setting === -1 )
+ if ( setting === -1 || is_old )
return '';
else if ( delay > (setting * 2) )
@@ -127,9 +136,11 @@ metadata.player_stats = {
player_cont.$('.js-stats-toggle').click();
},
- tooltip: function(stats, delay, is_old) {
+ tooltip: function(stats, delay, is_old, player_cont, delayed) {
+ delayed = delayed ? 'Your local clock seems to be off by roughly ' + (Math.round(this._ws_server_offset / 10) / 100).toFixed(2) + ' seconds, and that could be making this inaccurate.
' : '';
+
if ( ! stats || ! stats.hls_latency_broadcaster )
- return 'Stream Latency';
+ return delayed + 'Stream Latency';
var bitrate;
if ( stats.playback_bytes_per_second )
@@ -137,7 +148,7 @@ metadata.player_stats = {
else
bitrate = Math.round(stats.current_bitrate * 100) / 100;
- return (is_old ? 'Video Information
' +
+ return delayed + (is_old ? 'Video Information
' +
'Broadcast ' + utils.time_to_string(Math.floor(delay), true) + ' Ago
' : 'Stream Latency
') +
'Video: ' + stats.vid_width + 'x' + stats.vid_height + 'p' + stats.current_fps + '
' +
'Playback Rate: ' + utils.number_commas(bitrate) + ' Kbps
' +
@@ -156,7 +167,7 @@ metadata.chatters = {
if ( ! room || ! this.settings.chatter_count )
return null;
- return utils.number_commas(Object.keys(room.room.get('ffz_chatters') || {}).length);
+ return utils.number_commas((room.room.get('ffz_chatters') || []).length);
},
tooltip: 'Currently in Chat'
diff --git a/src/ui/dark.js b/src/ui/dark.js
index 48d9774a..4cee954b 100644
--- a/src/ui/dark.js
+++ b/src/ui/dark.js
@@ -133,6 +133,10 @@ FFZ.settings_info.dark_twitch = {
if ( this.has_bttv )
return;
+ var RH = this._roomv && this._roomv.get('ffz_recent_el');
+ if ( RH )
+ RH.classList.toggle('dark', val);
+
(this.is_clips ? document.querySelector('html') : document.body).classList.toggle("ffz-dark", val);
var Settings = utils.ember_settings();
diff --git a/src/ui/following-count.js b/src/ui/following-count.js
index 41b1a0ec..1cee2850 100644
--- a/src/ui/following-count.js
+++ b/src/ui/following-count.js
@@ -224,7 +224,9 @@ FFZ.prototype._build_following_tooltip = function(el) {
(uptime > 0 ? '' + constants.CLOCK + ' ' + utils.duration_string(uptime) + '' : '') +
'' + constants.LIVE + ' ' + utils.number_commas(stream.viewers) + '' +
'' + utils.sanitize(stream.channel.display_name || stream.channel.name) + '
' +
- '' + (stream.channel.game === 'Creative' ? 'Being Creative' : (stream.channel.game ? 'Playing ' + utils.sanitize(stream.channel.game) : 'Not Playing')) + (tags ? ' | ' + _.pluck(tags, "text").join(" ") : '') + '';
+ '' +
+ (stream.stream_type === 'watch_party' ? 'Vodcast ' : '') +
+ (stream.channel.game === 'Creative' ? 'Being Creative' : (stream.channel.game ? 'Playing ' + utils.sanitize(stream.channel.game) : 'Not Playing')) + (tags ? ' | ' + _.pluck(tags, "text").join(" ") : '') + '';
}
if ( filtered )
diff --git a/src/ui/logviewer.js b/src/ui/logviewer.js
index f69a28f0..ca0ea742 100644
--- a/src/ui/logviewer.js
+++ b/src/ui/logviewer.js
@@ -770,7 +770,7 @@ FFZ.mod_card_pages.notes = {
utils.logviewer.get("comments/" + room_id + "?topic=" + user_id, token)
.then(utils.json).then(function(data) {
- f.log("[LV] Comments: " + user_id + " in " + room_id, data);
+ //f.log("[LV] Comments: " + user_id + " in " + room_id, data);
history.classList.remove('loading');
// We want to listen to get new notes for this user.
diff --git a/src/ui/my_emotes.js b/src/ui/my_emotes.js
index 17469e8d..a917c7be 100644
--- a/src/ui/my_emotes.js
+++ b/src/ui/my_emotes.js
@@ -2,7 +2,8 @@ var FFZ = window.FrankerFaceZ,
constants = require("../constants"),
utils = require("../utils"),
- BANNED_SETS = {"00000turbo":true};
+ BANNED_SETS = {"00000turbo":true},
+ EXTRA_INVENTORY = ['33563'];
// -------------------
@@ -154,6 +155,43 @@ FFZ.menu_pages.myemotes = {
},
render: function(view, container) {
+ /*var search_cont = utils.createElement('div', 'ffz-filter-container'),
+ search_input = utils.createElement('input', 'emoticon-selector__filter-input form__input js-filter-input text text--full-width'),
+ filtered_cont = utils.createElement('div', 'ffz-filter-children ffz-ui-sub-menu-page'),
+ was_filtered = false;
+
+ search_input.placeholder = 'Search for Emotes';
+ search_input.type = 'text';
+
+ filtered_cont.style.maxHeight = (parseInt(container.style.maxHeight) - 53) + 'px';
+
+ search_cont.appendChild(search_input);
+ container.appendChild(filtered_cont);
+ container.appendChild(search_cont);
+
+ search_input.addEventListener('input', function(e) {
+ var filter = (search_input.value || '').toLowerCase(),
+ groups = filtered_cont.querySelectorAll('.emoticon-grid');
+
+ for(var i=0; i < groups.length; i++) {
+ var el = groups[i],
+ emotes = el.querySelectorAll('.emoticon'),
+ hidden = true;
+
+ for(var j=0; j < emotes.length; j++) {
+ var em = emotes[j],
+ ehidden = filter.length && em.getAttribute('data-filter').indexOf(filter) === -1;
+
+ em.classList.toggle('hidden', ehidden);
+ hidden = hidden && ehidden;
+ }
+
+ el.classList.toggle('hidden', hidden);
+ el.classList.toggle('collapsable', ! filter.length);
+ }
+ });
+
+ container = filtered_cont;*/
FFZ.menu_pages.myemotes.render_lists.call(this, view, container, false);
}
},
@@ -199,7 +237,9 @@ FFZ.menu_pages.myemotes = {
gathered_emotes = [];
// Start with Twitch Sets
- var gathered_favorites = this.settings.favorite_emotes['twitch-inventory'] || [];
+ var gathered_favorites = this.settings.favorite_emotes['twitch-inventory'] || [],
+ gathered_channels = {},
+ other_channels = [];
for(var set_id in twitch_sets) {
if ( ! twitch_sets.hasOwnProperty(set_id) || ( ! favorites_only && ! this.settings.global_emotes_in_menu && set_id === '0' ) )
@@ -213,7 +253,7 @@ FFZ.menu_pages.myemotes = {
if ( ! set.length )
continue;
- if ( this._twitch_inventory_sets.indexOf(set_id) !== -1 ) {
+ if ( this._twitch_inventory_sets.indexOf(set_id) !== -1 || EXTRA_INVENTORY.indexOf(set_id) !== -1 ) {
for(var i=0; i < set.length; i++)
if ( ! favorites_only || gathered_favorites.indexOf(set[i].id) !== -1 )
gathered_emotes.push(set[i]);
@@ -228,6 +268,12 @@ FFZ.menu_pages.myemotes = {
if ( favorites_only && (! favorites_list || ! favorites_list.length) )
continue;
+ if ( menu_id !== 'unknown' ) {
+ var gathered = gathered_channels[menu_id] = gathered_channels[menu_id] || [];
+ gathered.push(set_id);
+ continue;
+ }
+
var sort_key = 0,
menu = FFZ.menu_pages.myemotes.draw_twitch_set.call(this, view, set_id, set, favorites_only);
@@ -240,6 +286,33 @@ FFZ.menu_pages.myemotes = {
sets.push([[sort_key, menu_id], menu]);
}
+ for(var menu_id in gathered_channels) {
+ var gathered = [],
+ stuff = gathered_channels[menu_id];
+
+ if ( ! stuff.length )
+ continue;
+
+ for(var i=0; i < stuff.length; i++) {
+ var set_id = stuff[i],
+ set = twitch_sets[set_id];
+ for(var j=0; j < set.length; j++)
+ gathered.push([set_id, set[j]]);
+ }
+
+ var sort_key = 0,
+ menu = FFZ.menu_pages.myemotes.draw_twitch_set.call(this, view, stuff[0], gathered, favorites_only);
+
+ if ( menu_id.indexOf('global') !== -1 )
+ sort_key = 100;
+ else if ( menu_id.substr(0,2) === '--' || menu_id === 'turbo' )
+ sort_key = 75;
+
+ if ( menu )
+ 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);
@@ -338,18 +411,22 @@ FFZ.menu_pages.myemotes = {
return true;
},
- toggle_section: function(heading, container) {
+ toggle_section: function(heading, container, set_state) {
var menu = heading.parentElement,
set_id = menu.getAttribute('data-set'),
collapsed_list = this.settings.emote_menu_collapsed,
- is_collapsed = collapsed_list.indexOf(set_id) === -1;
+ has_state = set_state !== undefined,
+ is_collapsed = has_state ? set_state : collapsed_list.indexOf(set_id) === -1;
- if ( ! is_collapsed )
- collapsed_list.removeObject(set_id);
- else
- collapsed_list.push(set_id);
+ if ( ! has_state ) {
+ if ( ! is_collapsed )
+ collapsed_list.removeObject(set_id);
+ else
+ collapsed_list.push(set_id);
+
+ this.settings.set('emote_menu_collapsed', collapsed_list, true);
+ }
- this.settings.set('emote_menu_collapsed', collapsed_list, true);
menu.classList.toggle('collapsed', !is_collapsed);
if ( is_collapsed )
@@ -382,7 +459,7 @@ FFZ.menu_pages.myemotes = {
menu.classList.add('collapsable');
menu.appendChild(heading);
menu.classList.toggle('collapsed', collapsed);
- heading.addEventListener('click', function() { FFZ.menu_pages.myemotes.toggle_section.bind(f)(this, emotes); });
+ heading.addEventListener('click', function() { FFZ.menu_pages.myemotes.toggle_section.bind(f)(this, emotes); });
}
var set = [];
@@ -420,6 +497,7 @@ FFZ.menu_pages.myemotes = {
em.classList.toggle('ffz-is-favorite', favorites_only);
em.setAttribute('data-ffz-emoji', emoji.code);
+ em.setAttribute('data-filter', emoji.name.toLowerCase() + ' :' + emoji.short_name.toLowerCase() + ':');
em.alt = emoji.raw;
em.addEventListener('click', this._add_emote.bind(this, view, emoji.raw, "emoji", emoji.raw));
@@ -502,6 +580,11 @@ FFZ.menu_pages.myemotes = {
}
set.sort(function(a,b) {
+ if ( Array.isArray(a) )
+ a = a[1];
+ if ( Array.isArray(b) )
+ b = b[1];
+
var an = a.code.toLowerCase(),
bn = b.code.toLowerCase();
@@ -514,8 +597,16 @@ FFZ.menu_pages.myemotes = {
for(var i=0; i < set.length; i++) {
var emote = set[i],
- code = constants.KNOWN_CODES[emote.code] || emote.code,
- is_favorite = favorites.indexOf(emote.id) !== -1;
+ esid = set_id,
+ favs = favorites;
+ if ( Array.isArray(emote) ) {
+ esid = emote[0];
+ emote = emote[1];
+ favs = this.settings.favorite_emotes["twitch-" + esid] || [];
+ }
+
+ var code = constants.KNOWN_CODES[emote.code] || emote.code,
+ is_favorite = favs.indexOf(emote.id) !== -1;
if ( favorites_only && ! is_favorite )
continue;
@@ -525,6 +616,7 @@ FFZ.menu_pages.myemotes = {
em.className = 'emoticon ffz-tooltip ffz-can-favorite';
em.setAttribute('data-emote', emote.id);
+ em.setAttribute('data-filter', code.toLowerCase());
em.alt = code;
em.classList.toggle('ffz-favorite', is_favorite);
@@ -541,13 +633,13 @@ FFZ.menu_pages.myemotes = {
em.style.backgroundImage = img_set;
}
- em.addEventListener("click", function(id, c, e) {
+ em.addEventListener("click", function(id, c, q, e) {
e.preventDefault();
if ( (e.shiftKey || e.shiftLeft) && f.settings.clickable_emoticons )
window.open("https://twitchemotes.com/emote/" + id);
else
- this._add_emote(view, c, "twitch-" + set_id, id, e);
- }.bind(this, emote.id, code));
+ this._add_emote(view, c, "twitch-" + q, id, e);
+ }.bind(this, emote.id, code, esid));
c++;
emotes.appendChild(em);
@@ -634,6 +726,7 @@ FFZ.menu_pages.myemotes = {
em.setAttribute('data-ffz-emote', emote.id);
em.setAttribute('data-ffz-set', set.id);
+ em.setAttribute('data-filter', emote.name.toLowerCase());
em.style.backgroundImage = 'url("' + emote.urls[1] + '")';
em.style.backgroundImage = '-webkit-' + img_set;
diff --git a/src/utils.js b/src/utils.js
index b07ffb5b..626c9158 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -1181,6 +1181,7 @@ module.exports = FFZ.utils = {
return (loyalty ? '.ffz-no-loyalty ' : '') + '.from-display-preview[data-room="' + room_id + '"] .badge.' + badge_id + (loyalty ? '' : '.version-' + version) +
(loyalty ? ',.ffz-no-loyalty ' : ',') + '.chat-line[data-room="' + room_id + '"] .badge.' + badge_id + (loyalty ? '' : '.version-' + version) + '{' +
'background-color:transparent;' +
+ WEBKIT + 'mask-image: none;' +
'background-image:url("' + img_1x + '");' +
'background-image:' + WEBKIT + 'image-set(url("' + img_1x + '") 1x' + (img_2x ? ',url("' + img_2x + '") 2x' : '') + (img_4x ? ',url("' + img_4x + '") 4x' : '') + ')}';
},
diff --git a/style.css b/style.css
index e16d36a8..293d3053 100644
--- a/style.css
+++ b/style.css
@@ -1,5 +1,6 @@
/* Fix Tooltip Opacity */
+body[data-page^="ember#"] { overflow: hidden }
body > div.tipsy { opacity: 1 !important; }
body > div.tipsy .tipsy-inner { background-color: rgba(0,0,0,0.8); }
body > div.tipsy .tipsy-arrow { opacity: 0.8; }
@@ -35,6 +36,7 @@ body > div.tipsy .tipsy-arrow { opacity: 0.8; }
.ffz-hide-thumb-info-on-hover .video.item:hover .card__meta,
.ffz-hide-thumb-info-on-hover .video.item:hover .progress-bar-wrapper,
.ffz-hide-thumb-info-on-hover .card-carousel__item:hover .card__boxpin,
+.ffz-hide-thumb-info-on-hover .ffz-directory-preview:hover .card__boxpin,
.player[data-paused="false"] #js-follow-panel,
body:not(.ffz-theater-basic-stats) .player-userinfo__game,
@@ -111,7 +113,7 @@ body:not(.ffz-show-bits-tags) .bits-tag--container,
}
.ffz-channel-bar-bottom .subscription-modal__balloon {
- top: -220px !important;
+ top: -400px !important;
}
.cn-hosting--bottom .ffz-channel-options .balloon {
@@ -735,6 +737,8 @@ body.ffz-bttv-dark .ffz-ui-toggle.blue.live:hover svg.svg-emoticons path { fill:
margin: 11px 13px;
}
+.ffz-player-reset svg { padding: 0 3px }
+
.player-menu__menu,
.ffz-ui-sub-menu-page,
.ffz-ui-menu-page { overflow-y: auto; }
@@ -919,40 +923,48 @@ span.ffz-handle:after {
span.ffz-handle:after { left: 8px }
-.ffz-ui-popup.ui-moved span.ffz-handle { width: 24px; cursor: pointer; }
+.ui-moved span.ffz-handle { width: 24px; cursor: pointer; }
-.ffz-ui-popup.ui-moved span.ffz-handle:before,
-.ffz-ui-popup.ui-moved span.ffz-handle:after {
+.ui-moved span.ffz-handle:before,
+.ui-moved span.ffz-handle:after {
left: 11px;
border-color: #333;
}
-.ffz-ui-popup.ui-moved span.ffz-handle:before { transform: rotate(45deg); }
-.ffz-ui-popup.ui-moved span.ffz-handle:after { transform: rotate(-45deg); }
+.ui-moved span.ffz-handle:before { transform: rotate(45deg); }
+.ui-moved span.ffz-handle:after { transform: rotate(-45deg); }
+
+.ffz-dark .ffz-recent-expando span.ffz-handle:before,
+.ffz-dark .ffz-recent-expando span.ffz-handle:after,
.app-main.theatre span.ffz-handle:before,
.chat-container.dark span.ffz-handle:before,
.ember-chat-container.dark span.ffz-handle:before,
-body.ffz-bttv-dark .ffz-ui-popup span.ffz-handle:before,
+body.ffz-bttv-dark span.ffz-handle:before,
.app-main.theatre span.ffz-handle:after,
.chat-container.dark span.ffz-handle:after,
.ember-chat-container.dark span.ffz-handle:after,
-body.ffz-bttv-dark .ffz-ui-popup span.ffz-handle:after {
+body.ffz-bttv-dark span.ffz-handle:after {
border-color: #666;
}
-.app-main.theatre .ffz-ui-popup.ui-moved span.ffz-handle:before,
-.chat-container.dark .ffz-ui-popup.ui-moved span.ffz-handle:before,
-.ember-chat-container.dark .ffz-ui-popup.ui-moved span.ffz-handle:before,
-body.ffz-bttv-dark .ffz-ui-popup.ui-moved span.ffz-handle:before,
-.app-main.theatre .ffz-ui-popup.ui-moved span.ffz-handle:after,
-.chat-container.dark .ffz-ui-popup.ui-moved span.ffz-handle:after,
-.ember-chat-container.dark .ffz-ui-popup.ui-moved span.ffz-handle:after,
-body.ffz-bttv-dark .ffz-ui-popup.ui-moved span.ffz-handle:after {
+.app-main.theatre .ui-moved span.ffz-handle:before,
+.chat-container.dark .ui-moved span.ffz-handle:before,
+.ember-chat-container.dark .ui-moved span.ffz-handle:before,
+body.ffz-bttv-dark .ui-moved span.ffz-handle:before,
+.app-main.theatre .ui-moved span.ffz-handle:after,
+.chat-container.dark .ui-moved span.ffz-handle:after,
+.ember-chat-container.dark .ui-moved span.ffz-handle:after,
+body.ffz-bttv-dark .ui-moved span.ffz-handle:after {
border-color: #d3d3d3;
}
+.ffz-recent-expando > span.ffz-handle {
+ float: left;
+ margin: -3px 5px -3px -5px;
+}
+
.ffz-ui-popup ul.menu li.title > span.ffz-handle {
float: left;
margin: 5px;
@@ -1279,6 +1291,7 @@ body:not(.ffz-bttv) .dropmenu.share { margin-bottom: 0; }
.theatre .conversation-window .conversation-content::-webkit-scrollbar-thumb,
.theatre .conversations-list .conversations-list-inner::-webkit-scrollbar-thumb,
+.ffz-dark .chat-history::-webkit-scrollbar-thumb,
.theatre .chat-history::-webkit-scrollbar-thumb,
.theatre .emoticon-selector-box .all-emotes::-webkit-scrollbar-thumb,
.theatre .ffz-ui-menu-page::-webkit-scrollbar-thumb,
@@ -1623,8 +1636,10 @@ body:not(.ffz-bttv) .chat-container:not(.chatReplay) .more-messages-indicator {
margin: 10px 0;
}
-.ffz-wide-tip hr {
+.tipsy-inner hr {
margin: 5px 0;
+ border-bottom-width: 1px;
+ border-bottom-style: solid;
}
.ffz-wide-tip .tipsy-inner {
@@ -1908,7 +1923,7 @@ th.ffz-row-switch {
}
#ffz-group-tabs .button {
- height: 18px;
+ height: 30px;
padding-bottom: 10px;
margin-bottom: -10px;
margin-right: 4px;
@@ -2111,6 +2126,11 @@ body.ffz-minimal-chat-input .ember-chat .chat-interface .textarea-contain textar
overflow-y: auto;
}
+.chat-messages .tse-scroll-content,
+.chat-history {
+ will-change: scroll-position, contents;
+}
+
.moderation-card .chat-history.live-history {
max-height: 200px;
}
@@ -2487,8 +2507,9 @@ body:not([data-current-path^="user."]) .ffz-sidebar-swap .ember-chat .chat-inter
}
+.ffz-no-blue .theme--dark .sc-collapsed-header,
.ffz-no-blue .theme--dark .sc-header { box-shadow: 0 -0.1rem 0 #5c5c5c inset }
-.ffz-no-blue .theme--dark .sc-card:hover { box-shadow: -0.1rem 0 0 #414141 inset }
+.ffz-no-blue .theme--dark .js-sc-card:hover { box-shadow: -0.1rem 0 0 #414141 inset }
.ffz-no-blue .theme--dark .social-column { box-shadow: -0.1rem 0 0 #2b2b2b inset}
.ffz-no-blue .theme--dark .form__input,
@@ -2511,7 +2532,7 @@ body:not([data-current-path^="user."]) .ffz-sidebar-swap .ember-chat .chat-inter
background-color: rgba(25,25,25,.5);
}
-.ffz-no-blue .theme--dark .sc-card:hover,
+.ffz-no-blue .theme--dark .js-sc-card:hover,
.ffz-no-blue .theme--dark .sc-toggle:hover,
.ffz-no-blue .warp__item a:not(.warp__logo):hover {
background-color: #2b2b2b;
@@ -3865,8 +3886,10 @@ div.metadata-box {
.ban-tip { border-bottom: 1px dotted rgba(102,102,102,0.5); }
+.ffz-clickable-mentions .ffz-recent-messages .chat-line .user-token,
.ffz-clickable-mentions .pinned-cheers .chat-line .user-token,
.ffz-clickable-mentions .chat-display .chat-line .user-token { font-weight: bold }
+.ffz-clickable-mentions .ffz-recent-messages .chat-line .user-token:hover,
.ffz-clickable-mentions .pinned-cheers .chat-line .user-token:hover,
.ffz-clickable-mentions .chat-display .chat-line .user-token:hover {
text-decoration: underline;
@@ -4168,6 +4191,100 @@ body.ffz-sidebar-swap .app-main.theatre #main_col:not(.expandRight) #player[data
.itad-balloon table th:not(:first-child),
.itad-balloon table td:not(:first-child) { text-align: right }
+.ffz-has-recent-messages .resub-wrap {
+ padding-top: 30px;
+}
+
+.chat-messages[data-pinned_height="30"],
+.ffz-has-recent-messages .sticky-message,
+.ffz-has-recent-messages .chat-messages {
+ top: 30px;
+}
+
+.chat-messages[data-pinned_height="76"] { top: 76px }
+.ffz-has-recent-messages .chat-messages[data-pinned_height="30"] { top: 60px }
+.ffz-has-recent-messages .chat-messages[data-pinned_height="76"] { top: 106px }
+
+.ffz-recent-messages {
+ background-color: #efeef1;
+ border-bottom: 1px solid #dad8de;
+ z-index: 1000;
+ overflow: hidden;
+ position: absolute !important;
+ top: 0;
+ left: 0;
+ right: 0;
+ transition: height ease-in-out 100ms;
+ height: 30px;
+ box-shadow: 0 10px 5px -3px rgba(239,238,241,0.5);
+}
+
+.ffz-recent-messages.ui-moved {
+ height: auto;
+ right: auto;
+ width: 340px;
+ border: 1px solid #dad8de;
+}
+
+.ffz-recent-messages.ui-moved .pill {
+ display: none;
+}
+
+.ffz-recent-messages .ffz-recent-expando {
+ background-color: #efeef1;
+ padding: 5px 10px;
+ border-bottom: 1px solid #dad8de;
+ color: #333;
+ cursor: move;
+ position: relative;
+ z-index: 1;
+}
+
+.ffz-recent-expando .pill {
+ float: right;
+ font-size: 100%;
+ margin-top: 3px;
+}
+
+.ffz-recent-messages .chat-history {
+ top: -150px;
+ position: relative;
+ height: 150px;
+ transition: top ease-in-out 75ms;
+}
+
+.ffz-recent-messages:not(.ui-moved):hover {
+ height: 180px;
+}
+
+.ffz-recent-messages.ui-moved .chat-history,
+.ffz-recent-messages:not(.ui-moved):hover .chat-history {
+ top: 0px;
+}
+
+.ffz-recent-messages.ui-moved .chat-history {
+ min-height: 150px;
+ height: auto;
+}
+
+.ffz-dark .ffz-recent-expando,
+.theatre .ffz-recent-expando,
+.dark .ffz-recent-expando,
+.force-dark .ffz-recent-expando {
+ background-color: #242424;
+ border-color: #474747;
+ color: #ccc;
+}
+
+.ffz-dark .ffz-recent-messages,
+.theatre .ffz-recent-messages,
+.dark .ffz-recent-messages,
+.force-dark .ffz-recent-messages {
+ background-color: #191919;
+ border-color: #474747;
+ box-shadow: 0 10px 5px -3px rgba(25,25,25,0.5);
+}
+
/*
H O T * G A R B A G E