1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-08-03 00:18:31 +00:00

3.5.355. Auto-Pause Hosted Channels. CSS tweaks. Refactor chat hover pause so that VOD chat uses the same code. Do per-channel badge CSS for chat replay. Stuff.

This commit is contained in:
SirStendec 2016-10-27 12:49:31 -04:00
parent 1b4ac0bad8
commit 34eb700c14
13 changed files with 231 additions and 646 deletions

View file

@ -1,6 +1,31 @@
<div class="list-header">3.5.355 <time datetime="2016-10-27">(2016-10-27)</time></div>
<ul class="chat-menu-content menu-side-padding">
<li>Added: Auto-Pause Hosted Channels is back! The player doesn't break anymore if you try to pause it immediately.</li>
</ul>
<div class="list-header">3.5.354 <time datetime="2016-10-26">(2016-10-26)</time></div>
<ul class="chat-menu-content menu-side-padding">
<li>Fixed: Display In-Line Mod Icons was breaking for any key other than Ctrl.</li>
<li>Fixed: Minor CSS tweaks.</li>
<li>Fixed: Ensure loyalty badges display correctly in Chat Replay.</li>
<li>Changed: Refactor Chat Replay hover pause.</li>
</ul>
<div class="list-header">3.5.353 <time datetime="2016-10-25">(2016-10-25)</time></div>
<ul class="chat-menu-content menu-side-padding">
<li>Fixed: Only use ctrl to freeze when the mouse is over the chat pane.</li>
<li>Fixed: Group chat got broken.</li>
</ul>
<div class="list-header">3.5.352 <time datetime="2016-10-25">(2016-10-25)</time></div>
<ul class="chat-menu-content menu-side-padding">
<li>Changed: More modifier CSS work.</li>
</ul>
<div class="list-header">3.5.351 <time datetime="2016-10-25">(2016-10-25)</time></div>
<ul class="chat-menu-content menu-side-padding">
<li>Added: Spooks.</li>
<li>Added: <code>/untimeout</code> support.</li>
<li>Fixed: Bits visibility and moderation card positioning.</li>
<li>Fixed: Modifer emote CSS was still not good.</li>
<li>Fixed: BetterTTV + Modifier Emotes</li>
</ul>

View file

@ -855,19 +855,23 @@ body.ffz-dark:not([data-page="teams#show"]),
/* Dashboard */
.ffz-dark .card-carousel__button,
.ffz-dark .carousel__button {
background-color: #101010;
}
.ffz-dark .card-carousel__arrow:before,
.ffz-dark .carousel__arrow:before {
border-color: #a68ed2;
}
.ffz-dark .card-carousel__button:hover .card-carousel__arrow:before
.ffz-dark .carousel__button:hover .carousel__arrow:before {
border-color: #fff;
}
.ffz-dark .brick.brick--theme-grey,
.ffz-dark .card-carousel__button:hover
.ffz-dark .carousel__button:hover {
background-color: #191919;
}
@ -1110,6 +1114,7 @@ body.ffz-dark:not([data-page="teams#show"]),
/* Playlist */
.ffz-dark .cn-chat-replay-header,
.ffz-dark .ember-chat .chat-header {
box-shadow: inset 0 -1px 0 0 rgba(255,255,255,0.2);
}

View file

@ -173,6 +173,9 @@ FFZ.ffz_commands.reload = function(room, args) {
var f = this,
promises = [];
// Feature Friday. There's no feedback possible so don't use a promise.
this.check_ff();
// Badge Information
promises.push(new Promise(function(done, fail) {
f.load_badges(function(success, badge_count, badge_total, badge_data) {

View file

@ -17,6 +17,10 @@ var FFZ = window.FrankerFaceZ,
label: '/timeout &lt;user&gt; <i>[duration=600] [reason]</i>',
info: 'Temporarily Ban User'
},
untimeout: {
label: '/untimeout &lt;user&gt;',
info: 'Unban Temporarily-Banned User'
},
clear: {info: 'Clear Chat for All Users'},
slow: {

View file

@ -254,11 +254,11 @@ FFZ.prototype.setup_layout = function() {
var size = this.get('fullSizePlayerDimensions');
return '<style>' +
'.ffz-small-player:not(.ffz-bttv)[data-current-path^="user.channel."] .app-main:not(.theatre) #player,' +
'.ffz-small-player:not(.ffz-bttv)[data-current-path^="user."] .app-main:not(.theatre) #player,' +
'.dynamic-player, .dynamic-player object, .dynamic-player video {' +
'width:' + size.width + 'px !important;' +
'height:' + size.height + 'px !important}' +
'.ffz-small-player:not(.ffz-bttv)[data-current-path^="user.channel."] .app-main:not(.theatre) #player,' +
'.ffz-small-player:not(.ffz-bttv)[data-current-path^="user."] .app-main:not(.theatre) #player,' +
'.dynamic-target-player, .dynamic-target-player object, .dynamic-target-player video {' +
'width:' + size.width + 'px !important;' +
'height:' + size.targetHeight + 'px !important}' +

View file

@ -59,7 +59,7 @@ FFZ.settings_info.player_volume_bar = {
};
/*FFZ.settings_info.player_pause_hosts = {
FFZ.settings_info.player_pause_hosts = {
type: "select",
options: {
0: "Disabled",
@ -73,7 +73,7 @@ FFZ.settings_info.player_volume_bar = {
category: "Player",
name: "Auto-Pause Hosted Channels",
help: "Automatically pause hosted channels if you paused the channel doing the hosting, or just pause all hosts."
}*/
}
// ---------------
@ -116,7 +116,7 @@ FFZ.prototype.modify_twitch_player = function(player) {
f.players[channel_id] = undefined;
},
/*insertPlayer: function(ffz_reset) {
insertPlayer: function(ffz_reset) {
// We want to see if this is a hosted video on a play
var should_start_paused = this.get('shouldStartPaused'),
channel_id = this.get('hostChannel.name'),
@ -128,9 +128,7 @@ FFZ.prototype.modify_twitch_player = function(player) {
this.set('shouldStartPaused', false);
// Alternatively, depending on the setting...
else if (
(f.settings.player_pause_hosts === 1 && this.get('ffz_original_paused') ) ||
(f.settings.player_pause_hosts === 2 && is_hosting) )
else if ( f.settings.player_pause_hosts === 2 && is_hosting )
this.set('shouldStartPaused', true);
this._super();
@ -138,7 +136,7 @@ FFZ.prototype.modify_twitch_player = function(player) {
// Restore the previous value so it doesn't mess anything up.
this.set('shouldStartPaused', should_start_paused);
}.on('didInsertElement'),*/
}.on('didInsertElement'),
postPlayerSetup: function() {
this._super();
@ -168,21 +166,38 @@ FFZ.prototype.modify_twitch_player = function(player) {
Ember.run.next(this.insertPlayer.bind(this, true));
},
/*ffzUpdatePlayerPaused: function() {
ffzUpdatePlayerPaused: function() {
var channel_id = this.get('hostChannel.name'),
hosted_id = this.get('channel.name'),
is_hosting = channel_id !== hosted_id,
is_paused = this.get('player.paused');
if ( ! is_hosting )
this.set('ffz_original_paused', is_paused);
player = this.get('player'),
is_paused = player.paused;
f.log("Player Pause State for " + channel_id + ": " + is_paused);
},*/
if ( ! is_hosting ) {
this.set('ffz_host_paused', false);
this.set('ffz_original_paused', is_paused);
return;
}
if ( ! f.settings.player_pause_hosts || is_paused || this.get('ffz_host_paused') )
return;
this.set('ffz_host_paused', true);
if ( this.get('ffz_original_paused') || f.settings.player_pause_hosts === 2 )
player.pause();
},
ffzHostChange: function() {
this.set('ffz_host_paused', false);
}.observes('channel'),
ffzPostPlayer: function() {
var channel_id = this.get('hostChannel.name'),
var f = this,
channel_id = this.get('hostChannel.name'),
hosted_id = this.get('channel.name'),
is_hosting = channel_id !== hosted_id,
@ -192,11 +207,11 @@ FFZ.prototype.modify_twitch_player = function(player) {
this.set('ffz_post_player', true);
/*if ( ! is_hosting )
if ( ! is_hosting )
this.set('ffz_original_paused', player.paused);
player.addEventListener('pause', this.ffzUpdatePlayerPaused.bind(this));
player.addEventListener('play', this.ffzUpdatePlayerPaused.bind(this));*/
player.addEventListener('play', this.ffzUpdatePlayerPaused.bind(this));
// Make the stats window draggable and fix the button.
var stats = this.$('.player .js-playback-stats');

View file

@ -184,7 +184,8 @@ FFZ.prototype.format_ban_notice = function(username, is_me, duration, count, rea
return (is_me ? 'You have' : '<span data-user="' + utils.quote_san(username) + '" class="ban-target html-tooltip" title="' + utils.quote_attr(name[1] || '') + '">' + name[0] + '</span> has') +
' been ' + (duration_tip.length ? '<span class="ban-tip html-tooltip" title="' + utils.quote_attr(duration_tip.join('<br>')) + '">' : '') + (duration === -Infinity ? 'unbanned' :
(duration === 1 ? 'purged' : isFinite(duration) ? 'timed out for ' + utils.duration_string(duration) : 'banned')) +
(duration === -1 ? 'untimed out' :
(duration === 1 ? 'purged' : isFinite(duration) ? 'timed out for ' + utils.duration_string(duration) : 'banned'))) +
(count > 1 ? ' (' + utils.number_commas(count) + ' times)' : '') +
(moderators && moderators.length ? ' by ' + utils.sanitize(moderators.join(', ')) : '') + (duration_tip.length ? '</span>' : '') +
(reasons && reasons.length ? ' with reason' + utils.pluralize(reasons.length) + ': ' + utils.sanitize(reasons.join(', ')) : '.');
@ -383,7 +384,8 @@ FFZ.HoverPause = {
ffzEnableFreeze: function() {
var el = this.get('element'),
messages = el && el.querySelector(this.get('ffz_freeze_selector'));
scroller = this.get('chatMessagesScroller'),
messages = (scroller && scroller[0]) || (el && el.querySelector(this.get('ffz_freeze_selector')));
if ( ! messages )
return;
@ -534,11 +536,11 @@ FFZ.HoverPause = {
if ( ! this._ffz_freeze_outside && cmi > 1 )
this.get('element').classList.toggle('show-mod-icons',
cmi === 2 ? this._ffz_freeze_ctrl :
cmd === 3 ? this._ffz_freeze_meta :
cmi === 3 ? this._ffz_freeze_meta :
cmi === 4 ? this._ffz_freeze_alt :
this._ffz_freeze_shift);
if ( this._ffz_outside || f.settings.chat_hover_pause < 2 )
if ( this._ffz_freeze_outside || f.settings.chat_hover_pause < 2 )
return;
// Okay, so at this point we should change the state of the freeze?
@ -578,7 +580,7 @@ FFZ.HoverPause = {
if ( ! this._ffz_freeze_outside && cmi > 1 )
this.get('element').classList.toggle('show-mod-icons',
cmi === 2 ? this._ffz_freeze_ctrl :
cmd === 3 ? this._ffz_freeze_meta :
cmi === 3 ? this._ffz_freeze_meta :
cmi === 4 ? this._ffz_freeze_alt :
this._ffz_freeze_shift);
@ -593,19 +595,19 @@ FFZ.HoverPause = {
},
_prepareStickyBottom: function() {
var t = this;
var t = this,
scroller = this.get('chatMessagesScroller') || this._$chatMessagesScroller;
this._setStuckToBottom(true);
this._$chatMessagesScroller.on(this._scrollEvents, function(e) {
var a = t._$chatMessagesScroller;
if ( a && a[0] && ((!t.ffz_frozen && 'mousedown' === e.type) || 'wheel' === e.type || 'mousewheel' === e.type) ) {
var distance = a[0].scrollHeight - a[0].scrollTop - a[0].offsetHeight;
scroller.on(this._scrollEvents, function(e) {
if ( scroller && scroller[0] && ((!t.ffz_frozen && 'mousedown' === e.type) || 'wheel' === e.type || 'mousewheel' === e.type) ) {
var distance = scroller[0].scrollHeight - scroller[0].scrollTop - scroller[0].offsetHeight;
t._setStuckToBottom(distance <= 10);
}
});
},
ffzFixStickyBottom: function() {
this._$chatMessagesScroller.off(this._scrollEvents);
(this.get('chatMessagesScroller') || this._$chatMessagesScroller).off(this._scrollEvents);
this._prepareStickyBottom();
},
@ -614,7 +616,7 @@ FFZ.HoverPause = {
this._scrollToBottomRequested = true;
Ember.run.schedule("afterRender", function() {
if ( ! e.ffz_frozen && ! e.isDestroyed && ! e.isDestroying && e._scrollToBottomRequested ) {
var t = e._$chatMessagesScroller;
var t = e.get('chatMessagesScroller') || e._$chatMessagesScroller;
if ( t && t.length ) {
t[0].scrollTop = t[0].scrollHeight;
e._setStuckToBottom(true);
@ -638,6 +640,7 @@ FFZ.prototype.modify_room_component = function(component) {
ffz_init: function() {
f._roomv = this;
if ( ! f.has_bttv ) {
this.ffzFixStickyBottom();
this.ffzAddKeyHook();
@ -646,8 +649,41 @@ FFZ.prototype.modify_room_component = function(component) {
if ( f.settings.room_status )
this.ffzUpdateStatus();
}
// TODO: Fix bits visibility calculation
var actions = this._actions || {},
orig_show = actions.showModOverlay;
actions.showModOverlay = function(e) {
var Channel = utils.ember_resolve('model:deprecated-channel'),
chan = Channel && Channel.find && Channel.find({id: e.sender});
if ( ! chan ) {
f.log("Error opening mod card. model:deprecated-channel does not exist or does not have find!");
return orig_show && orig_show.call(this, e);
}
// Don't try loading the channel if it's already loaded. Don't make mod cards
// refresh the channel page when you click the broadcaster, basically.
if ( ! chan.get('isLoaded') )
chan.load();
this.set("showModerationCard", true);
// We pass in renderBottom and renderRight, which we use to reposition the window
// after we know how big it actually is. This doesn't work a lot of the time.
this.set("moderationCardInfo", {
user: chan,
renderTop: e.real_top || e.top,
renderLeft: e.left,
renderBottom: e.bottom,
renderRight: e.right,
isIgnored: this.get("tmiSession").isIgnored(e.sender),
isChannelOwner: this.get("session.userData.login") === e.sender,
profileHref: Twitch.uri.profile(e.sender),
isModeratorOrHigher: this.get("room.isModeratorOrHigher")
});
}
},
ffz_destroy: function() {
@ -658,6 +694,18 @@ FFZ.prototype.modify_room_component = function(component) {
this.ffzRemoveKeyHook();
},
ffzUpdateBits: function() {
var t = this,
channel = this.get('room.channel');
if ( ! channel )
return;
else if ( ! channel.get('isLoaded') )
channel.load().then(function() { t._initializeBits(channel) })
else
this._initializeBits(channel);
}.observes('room'),
ffzFreezeUpdateBuffer: function(val) {
var room = this.get('room');
if ( val === undefined )
@ -726,404 +774,6 @@ FFZ.prototype.modify_room_component = function(component) {
}, FFZ.HoverPause));
}
/*FFZ.prototype.modify_room_view = function(view) {
var f = this;
utils.ember_reopen_view(view, {
ffz_init: function() {
f._roomv = this;
this.ffz_frozen = false;
this.ffz_ctrl = false;
// Fix scrolling.
this._ffz_mouse_down = this.ffzMouseDown.bind(this);
if ( is_android )
// We don't unbind scroll because that messes with the scrollbar. ;_;
this._$chatMessagesScroller.bind('scroll', this._ffz_mouse_down);
this._$chatMessagesScroller.unbind('mousedown');
this._$chatMessagesScroller.bind('mousedown', this._ffz_mouse_down);
if ( f.settings.chat_hover_pause )
this.ffzEnableFreeze();
if ( f.settings.room_status )
this.ffzUpdateStatus();
var controller = this.get('controller');
if ( controller ) {
controller.reopen({
calcRecipientEligibility: function(e) {
// Because this doesn't work properly with multiple channel rooms
// by default, do it ourselves.
if ( controller.get('model.isGroupRoom') ) {
controller.set('isRecipientBitsIneligible', true);
controller.set('isBitsHelperShown', false);
controller.set('minimumBits', 0);
controller.set('isBitsTooltipActive', false);
return;
}
var id = controller.get('model.roomProperties._id'),
update = function(data) {
if ( controller.isDestroyed || controller.get('model.roomProperties._id') !== id )
return;
controller.set('model._ffz_bits_eligibility', data);
controller.set('isRecipientBitsIneligible', ! data.eligible);
controller.set('isBitsHelperShown', data.eligible);
controller.set('minimumBits', data.minBits);
if ( ! data.eligible )
controller.set('isBitsTooltipActive', false);
};
if ( id === undefined )
return;
var data = controller.get('model._ffz_bits_eligibility');
if ( data === undefined )
controller.get('bits').loadRecipientEligibility(id).then(update);
else
update(data);
},
submitButtonText: function() {
if ( this.get("model.isWhisperMessage") && this.get("model.isWhispersEnabled") )
return i18n("Whisper");
var wait = this.get("model.slowWait"),
msg = this.get("model.messageToSend") || "";
if ( (msg.charAt(0) === "/" && msg.substr(0, 4) !== "/me ") || !wait || !f.settings.room_status )
return i18n("Chat");
return utils.time_to_string(wait, false, false, true);
}.property("model.isWhisperMessage", "model.isWhispersEnabled", "model.slowWait")
});
Ember.propertyDidChange(controller, 'submitButtonText');
}
},
ffz_destroy: function() {
if ( f._roomv === this )
f._roomv = undefined;
if ( this._ffz_chat_display )
this._ffz_chat_display = undefined;
this.ffzDisableFreeze();
},
ffzOnKey: function(event) {
this.ffz_ctrl = event.ctrlKey;
this.ffz_alt = event.altKey;
this.ffz_shift = event.shiftKey;
this.ffz_meta = event.metaKey;
var cmi = f.settings.chat_mod_icon_visibility;
if ( ! this._ffz_outside && cmi > 1 )
this.get('element').classList.toggle('show-mod-icons',
cmi === 2 ? this.ffz_ctrl :
cmi === 3 ? this.ffz_meta :
cmi === 4 ? this.ffz_alt :
this.ffz_shift);
if ( this._ffz_outside || f.settings.chat_hover_pause < 2 )
return;
// Okay, so at this point we should change the state of the freeze?
var should_freeze = this.ffzShouldBeFrozen(),
freeze_change = this.ffz_frozen !== should_freeze;
if ( freeze_change )
if ( should_freeze )
this.ffzFreeze();
else
this.ffzUnfreeze();
},
ffzUpdateStatus: function() {
var room = this.get('controller.model'),
el = this.get('element'),
cont = el && el.querySelector('.chat-buttons-container');
if ( ! cont )
return;
var btn = cont.querySelector('button');
if ( f.has_bttv || ! f.settings.room_status ) {
jQuery(".ffz.room-state", cont).remove();
if ( btn )
btn.classList.remove('ffz-waiting');
return;
} else if ( btn ) {
btn.classList.toggle('ffz-waiting', (room && room.get('slowWait') || 0));
btn.classList.toggle('ffz-banned', (room && room.get('ffz_banned') || false));
}
var badge, id, info, vis_count = 0, label;
for(var i=0; i < STATUS_BADGES.length; i++) {
info = STATUS_BADGES[i];
id = 'ffz-stat-' + info[0];
badge = cont.querySelector('#' + id);
visible = typeof info[1] === "function" ? info[1].call(f, room) : room && room.get(info[1]);
if ( typeof visible === "string" )
visible = visible === "1";
label = typeof info[3] === "function" ? info[3].call(f, room) : undefined;
if ( ! badge ) {
badge = utils.createElement('span', 'ffz room-state stat float-right', (label || info[0]).charAt(0).toUpperCase() + '<span>' + (label || info[0]).substr(1).toUpperCase() + '</span>');
badge.id = id;
jQuery(badge).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'se')});
cont.appendChild(badge);
}
if ( label )
badge.innerHTML = (label || info[0]).charAt(0).toUpperCase() + '<span>' + (label || info[0]).substr(1).toUpperCase() + '</span>';
badge.title = typeof info[2] === "function" ? info[2].call(f, room) : info[2];
badge.classList.toggle('hidden', ! visible);
badge.classList.toggle('faded', info[4] !== undefined ? typeof info[4] === "function" ? info[4].call(f, room) : info[4] : false);
if ( visible )
vis_count++;
}
jQuery(".ffz.room-state", cont).toggleClass("truncated", vis_count > 3);
}.observes('controller.model'),
ffzEnableFreeze: function() {
var el = this.get('element'),
messages = el.querySelector('.chat-messages');
if ( ! messages )
return;
this._ffz_messages = messages;
if ( ! this._ffz_interval )
this._ffz_interval = setInterval(this.ffzPulse.bind(this), 200);
if ( ! this._ffz_mouse_move ) {
this._ffz_mouse_move = this.ffzMouseMove.bind(this);
messages.addEventListener('mousemove', this._ffz_mouse_move);
messages.addEventListener('touchmove', this._ffz_mouse_move);
}
if ( ! this._ffz_mouse_out ) {
this._ffz_mouse_out = this.ffzMouseOut.bind(this);
messages.addEventListener('mouseout', this._ffz_mouse_out);
}
// Monitor the Ctrl key.
if ( ! this._ffz_keyw ) {
this._ffz_keyw = this.ffzOnKey.bind(this);
document.body.addEventListener('keydown', this._ffz_keyw);
document.body.addEventListener('keyup', this._ffz_keyw);
}
},
ffzDisableFreeze: function() {
if ( this._ffz_interval ) {
clearInterval(this._ffz_interval);
this._ffz_interval = undefined;
}
this.ffzUnfreeze();
var messages = this._ffz_messages;
if ( ! messages )
return;
this._ffz_messages = undefined;
if ( this._ffz_mouse_move ) {
messages.removeEventListener('mousemove', this._ffz_mouse_move);
messages.removeEventListener('touchmove', this._ffz_mouse_move);
this._ffz_mouse_move = undefined;
}
if ( this._ffz_mouse_out ) {
messages.removeEventListener('mouseout', this._ffz_mouse_out);
this._ffz_mouse_out = undefined;
}
if ( this._ffz_keyw ) {
document.body.removeEventListener('keydown', this._ffz_keyw);
document.body.removeEventListener('keyup', this._ffz_keyw);
this._ffz_keyw = undefined;
}
},
ffzPulse: function() {
if ( this.ffz_frozen && ! this.ffzShouldBeFrozen() )
this.ffzUnfreeze();
},
ffzUnfreeze: function(from_stuck) {
this.ffz_frozen = false;
this._ffz_last_move = 0;
this.ffzUnwarnPaused();
if ( ! from_stuck && this.get('stuckToBottom') )
this._scrollToBottom();
},
ffzFreeze: function() {
this.ffz_frozen = true;
if ( this.get('stuckToBottom') ) {
this.set('controller.model.messageBufferSize', f.settings.scrollback_length + 150);
this.ffzWarnPaused();
}
},
ffzMouseDown: function(event) {
var t = this._$chatMessagesScroller;
if ( t && t[0] && ((!this.ffz_frozen && "mousedown" === event.type) || "mousewheel" === event.type || (is_android && "scroll" === event.type) ) ) {
var r = t[0].scrollHeight - t[0].scrollTop - t[0].offsetHeight;
this._setStuckToBottom(10 >= r);
}
},
ffzMouseOut: function(event) {
this._ffz_outside = true;
var e = this;
setTimeout(function() {
if ( e._ffz_outside ) {
if ( f.settings.chat_mod_icon_visibility > 1 )
e.get('element').classList.toggle('show-mod-icons', false);
e.ffzUnfreeze();
}
}, 25);
},
ffzShouldBeFrozen: function(since) {
if ( since === undefined )
since = Date.now() - this._ffz_last_move;
var hp = f.settings.chat_hover_pause;
return (this.ffz_ctrl && (hp === 2 || hp === 6)) ||
(this.ffz_meta && (hp === 3 || hp === 7)) ||
(this.ffz_alt && (hp === 4 || hp === 8)) ||
(this.ffz_shift && (hp === 5 || hp === 9)) ||
(since < 750 && (hp === 1 || hp > 5));
},
ffzMouseMove: function(event) {
// Store the last move time.
this._ffz_last_move = Date.now();
this._ffz_outside = false;
// If nothing of interest has happened, stop.
if ( event.altKey === this.ffz_alt && event.shiftKey === this.ffz_shift && event.ctrlKey === this.ffz_ctrl && event.metaKey === this.ffz_meta && event.screenX === this._ffz_last_screenx && event.screenY === this._ffz_last_screeny )
return;
// Grab a bit of state.
this.ffz_ctrl = event.ctrlKey;
this.ffz_alt = event.altKey;
this.ffz_shift = event.shiftKey;
this.ffz_meta = event.metaKey;
this._ffz_last_screenx = event.screenX;
this._ffz_last_screeny = event.screenY;
var cmi = f.settings.chat_mod_icon_visibility;
if ( ! this._ffz_outside && cmi > 1 )
this.get('element').classList.toggle('show-mod-icons',
cmi === 2 ? this.ffz_ctrl :
cmi === 3 ? this.ffz_meta :
cmi === 4 ? this.ffz_alt :
this.ffz_shift);
// Should the state have changed?
var should_freeze = this.ffzShouldBeFrozen(),
freeze_change = this.ffz_frozen !== should_freeze;
if ( freeze_change )
if ( should_freeze )
this.ffzFreeze();
else
this.ffzUnfreeze();
},
_scrollToBottom: _.throttle(function() {
var e = this,
s = this._$chatMessagesScroller;
//this.runTask(function() {
Ember.run.next(function(){
// Trying random performance tweaks for fun and profit!
(window.requestAnimationFrame||setTimeout)(function(){
if ( e.ffz_frozen || ! s || ! s.length )
return;
s[0].scrollTop = s[0].scrollHeight;
e._setStuckToBottom(true);
})
})
}, 200),
_setStuckToBottom: function(val) {
this.set("stuckToBottom", val);
var model = this.get("controller.model");
if ( model )
model.messageBufferSize = f.settings.scrollback_length + (val ? 0 : 150);
if ( ! val )
this.ffzUnfreeze(true);
},
// Warnings~!
ffzWarnPaused: function() {
var el = this.get('element'),
warning = el && el.querySelector('.chat-interface .more-messages-indicator.ffz-freeze-indicator');
if ( ! el )
return;
if ( ! warning ) {
warning = document.createElement('div');
warning.className = 'more-messages-indicator ffz-freeze-indicator';
var hp = f.settings.chat_hover_pause,
label = hp === 2 ? 'Ctrl Key' :
hp === 3 ? (constants.META_NAME + ' Key') :
hp === 4 ? 'Alt Key' :
hp === 5 ? 'Shift Key' :
hp === 6 ? 'Ctrl or Mouse' :
hp === 7 ? (constants.META_NAME + ' or Mouse') :
hp === 8 ? 'Alt or Mouse' :
hp === 9 ? 'Shift or Mouse' :
'Mouse Movement';
warning.innerHTML = '(Chat Paused Due to ' + label + ')';
var cont = el.querySelector('.chat-interface');
if ( ! cont )
return;
cont.insertBefore(warning, cont.childNodes[0])
}
warning.classList.remove('hidden');
},
ffzUnwarnPaused: function() {
var el = this.get('element'),
warning = el && el.querySelector('.chat-interface .more-messages-indicator.ffz-freeze-indicator');
if ( warning )
warning.classList.add('hidden');
}
});
}*/
// --------------------
// Command System
@ -1632,12 +1282,14 @@ FFZ.prototype._modify_room = function(room) {
//f.log("Login Moderation for " + this.get('id') + ' [' + room_id + ']', event);
// In case we get unexpected input, do the other thing.
if ( f.has_bttv || ["ban", "unban", "timeout"].indexOf(event.moderation_action) === -1 )
if ( f.has_bttv || ["ban", "unban", "timeout", "untimeout"].indexOf(event.moderation_action) === -1 )
return this._super(event);
var msg_id,
reason = event.args[2],
duration = event.moderation_action === 'unban' ? -Infinity : event.args[1];
duration = event.moderation_action === 'unban' ? -Infinity :
event.moderation_action === 'untimeout' ? -1 :
event.args[1];
if ( typeof duration === "string" )
duration = parseInt(duration);

View file

@ -50,49 +50,6 @@ FFZ.prototype.setup_vod_chat = function() {
}
/*FFZ.prototype.modify_vod_view = function(view) {
var f = this;
utils.ember_reopen_view(view, {
ffz_init: function() {
f._vodv = this;
var channel_id = this.get('context.channel.name');
if ( f.settings.auto_theater ) {
var player = f.players && f.players[channel_id] && f.players[channel_id].get('player');
if ( player )
player.setTheatre(true);
}
// Listen to scrolling.
this._ffz_scroller = this.ffzOnScroll.bind(this);
jQuery(this.get('element')).parents('.tse-scroll-content').on('scroll', this._ffz_scroller);
},
ffz_destroy: function() {
if ( f._vodv === this )
f._vodv = null;
if ( this._ffz_scroller ) {
jQuery(this.get('element')).parents('.tse-scroll-content').off('scroll', this._ffz_scroller);
this._ffz_scroller = null;
}
},
ffzOnScroll: function(event) {
// When we scroll past the bottom of the player, do stuff!
var top = event && event.target && event.target.scrollTop,
height = this.get('layout.playerSize.1');
if ( ! top )
top = jQuery(this.get('element')).parents('.tse-scroll-content').scrollTop();
document.body.classList.toggle('ffz-small-player', f.settings.small_player && top >= height);
}
});
}*/
FFZ.prototype.modify_vod_right_column = function(component) {
var f = this;
utils.ember_reopen_view(component, {
@ -113,172 +70,79 @@ FFZ.prototype.modify_vod_chat_display = function(component) {
var f = this,
VODService = utils.ember_lookup('service:vod-chat-service');
utils.ember_reopen_view(component, {
_prepareToolTips: function() {
this.$(".tooltip").tipsy({
live: true,
gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 's')
})
},
utils.ember_reopen_view(component, _.extend({
ffz_init: function() {
f._vodc = this;
// Load the room, if necessary
var room_id = this.get('video.channel.name');
if ( room_id && ! f.rooms[room_id] )
f.load_room(room_id); // TODO: Function to reprocess existing messages.
this.ffzUpdateBadges();
// Load the room, if nencessary.
var room_id = this.get('channel.name');
if ( room_id && ! f.rooms[room_id] )
f.load_room(room_id);
if ( ! f.has_bttv ) {
this.ffzFixStickyBottom();
this.ffzAddKeyHook();
this.ffz_frozen = false;
if ( f.settings.chat_hover_pause )
this.ffzEnableFreeze();
}
},
ffz_destroy: function() {
if ( f._vodc === this )
f._vodc = undefined;
// TODO: Function to unload the old room?
this.ffzDisableFreeze();
this.ffzRemoveKeyHook();
},
ffzEnableFreeze: function() {
var scroller = this.get('chatMessagesScroller');
if ( ! scroller )
return;
ffzUpdateBadges: function() {
var t = this,
channel_name = this.get('channel.name'),
owner_name = this.get('video.owner.name'),
owner_id = this.get('video.owner._id');
this._ffz_interval = setInterval(this.ffzPulse.bind(this), 200);
this._ffz_mouse_move = this.ffzMouseMove.bind(this);
this._ffz_mouse_out = this.ffzMouseOut.bind(this);
scroller.on('mousemove', this._ffz_mouse_move);
scroller.on('touchmove', this._ffz_mouse_move);
scroller.on('mouseout', this._ffz_mouse_out);
},
ffzDisableFreeze: function() {
if ( this._ffz_interval ) {
clearInterval(this._ffz_interval);
this._ffz_interval = undefined;
if ( channel_name !== owner_name ) {
t.set('ffzBadgeSet', null);
return Ember.propertyDidChange(t, 'badgeStyle');
}
this.ffzUnfreeze();
var scroller = this.get('chatMessagesScroller');
if ( ! scroller )
return;
if ( this._ffz_mouse_move ) {
scroller.off('mousemove', this._ffz_mouse_move);
scroller.off('touchmove', this._ffz_mouse_move);
this._ffz_mouse_move = undefined;
}
if ( this._ffz_mouse_out ) {
scroller.off('mouseout', this._ffz_mouse_out);
this._ffz_mouse_out = undefined;
}
},
ffzUnfreeze: function(from_stuck) {
this.ffz_frozen = false;
this._ffz_last_move = 0;
this.ffzUnwarnPaused();
if ( ! from_stuck && this.get('stuckToBottom') )
this._scrollToBottom();
},
ffzPulse: function() {
if ( this.ffz_frozen ) {
var elapsed = Date.now() - this._ffz_last_move;
if ( elapsed > 750 )
this.ffzUnfreeze();
}
},
ffzMouseOut: function(event) {
this._ffz_outside = true;
var e = this;
setTimeout(function() {
if ( e._ffz_outside )
e.ffzUnfreeze();
}, 25);
},
ffzMouseMove: function(event) {
this._ffz_last_move = Date.now();
this._ffz_outside = false;
if ( event.screenX === this._ffz_last_screenx && event.screenY === this._ffz_last_screeny )
return;
this._ffz_last_screenx = event.screenX;
this._ffz_last_screeny = event.screenY;
if ( this.ffz_frozen )
return;
this.ffz_frozen = true;
if ( this.get('stuckToBottom') ) {
VODService && VODService.set("messageBufferSize", f.settings.scrollback_length + 150);
this.ffzWarnPaused();
}
},
_scrollToBottom: _.throttle(function() {
var e = this,
scroller = e.get('chatMessagesScroller');
if ( ! scroller || ! scroller.length )
return;
Ember.run.next(function() {
(window.requestAnimationFrame||setTimeout)(function() {
if ( e.ffz_frozen )
return;
scroller[0].scrollTop = scroller[0].scrollHeight;
e._setStuckToBottom(true);
})
})
}, 300),
_setStuckToBottom: function(val) {
this.set("stuckToBottom", val);
VODService && VODService.set("messageBufferSize", f.settings.scrollback_length + (val ? 0 : 150));
if ( ! val )
this.ffUnfreeze(true);
},
ffzWarnPaused: function() {
var el = this.get('element'),
warning = el && el.querySelector('.chat-interface .more-messages-indicator.ffz-freeze-indicator');
if ( ! el )
return;
if ( ! warning ) {
warning = document.createElement('div');
warning.className = 'more-messages-indicator ffz-freeze-indicator';
warning.innerHTML = '(Chat Paused Due to Mouse Movement)';
var cont = el.querySelector('.chat-interface');
if ( ! cont )
return;
cont.insertBefore(warning, cont.childNodes[0])
}
warning.classList.remove('hidden');
},
ffzUnwarnPaused: function() {
var el = this.get('element'),
warning = el && el.querySelector('.chat-interface .more-messages-indicator.ffz-freeze-indicator');
if ( warning )
warning.classList.add('hidden');
fetch("https://badges.twitch.tv/v1/badges/channels/" + owner_id + "/display?language=" + (Twitch.receivedLanguage || "en"), {
headers: {
'Client-ID': constants.CLIENT_ID
}
}).then(utils.json).then(function(data) {
t.set('ffzBadgeSet', data.badge_sets);
Ember.propertyDidChange(t, 'badgeStyle');
});
},
badgeStyle: function() {
var badges = this.get('ffzBadgeSet');
if ( ! badges )
return this._super();
var room_id = this.get('channel.name'),
output = [];
for(var badge_id in badges) {
var versions = badges[badge_id] && badges[badge_id].versions || {};
for(var version in versions)
output.push(utils.room_badge_css(room_id, badge_id, version, versions[version]));
}
return Ember.String.htmlSafe('<style>' + output.join('') + '</style>');
}.property('badgeSet', 'ffzBadgeSet'),
ffzFreezeUpdateBuffer: function(val) {
if ( val === undefined )
val = this.get('stuckToBottom');
VODService && VODService.set("messageBufferSize", f.settings.scrollback_length + (val ? 0 : 150));
}
}, FFZ.HoverPause));
}

View file

@ -73,8 +73,8 @@ FFZ.prototype.setup_bttv = function(delay) {
if ( this._roomv ) {
// Disable Chat Pause
if ( this.settings.chat_hover_pause )
this._roomv.ffzDisableFreeze();
this._roomv.ffzRemoveKeyHook();
// And hide the status
if ( this.settings.room_status )

View file

@ -61,7 +61,7 @@ FFZ.channel_metadata = {};
// Version
var VER = FFZ.version_info = {
major: 3, minor: 5, revision: 351,
major: 3, minor: 5, revision: 355,
toString: function() {
return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || "");
}

View file

@ -937,7 +937,7 @@ FFZ.prototype.render_token = function(render_links, warn_links, render_bits, tok
//return `<img class="emoticon ffz-tooltip${cls||''}"${extra||''} src="${utils.quote_attr(src)}"${srcset ? ' srcset="' + utils.quote_attr(srcset) + '"' : ''} alt="${utils.quote_attr(token.altText)}">`;
var f = this, prefix = '', suffix = '';
if ( token.modifiers && token.modifiers.length ) {
prefix = '<span class="emoticon modified-emoticon">';
prefix = '<span class="emoticon modified-emoticon"' + (token.ffzEmote ? ' data-ffz-emote="' + token.ffzEmote + '"' : '') + '>';
suffix = _.map(token.modifiers, function(t) {
return '<span>' + f.render_token(render_links, warn_links, render_bits, t) + '</span>';
}).join('') + '</span>';

View file

@ -989,7 +989,7 @@ module.exports = FFZ.utils = {
m_top = margins[0 % l],
m_bottom = margins[2 % l];
output += '.modified-emoticon span img[data-ffz-emote="' + emote.id + '"] {' +
output += '.modified-emoticon span .emoticon[data-ffz-emote="' + emote.id + '"] {' +
'padding:' + m_top + 'px ' + m_right + 'px ' + m_bottom + 'px ' + m_left + 'px;' +
(emote.shrink_to_fit ? 'max-width: calc(100% - ' + (40 - m_left - m_right - (emote.extra_width || 0)) + 'px);' : '') +
'margin: 0 !important' +
@ -997,9 +997,9 @@ module.exports = FFZ.utils = {
}
return output +
'.activity-body img[data-ffz-emote="' + emote.id + '"],' +
'.chat-line img[data-ffz-emote="' + emote.id + '"] {' +
(emote.margins && (! emote.modifier || emote.modifier_offset) ? 'margin:' + emote.margins + ' !important;' : '') +
(emote.modifier && emote.margins ? '.ffz-bttv .emoticon[data-ffz-emote="' + emote.id + '"] { margin: ' + emote.margins + ' !important;}' : '') +
'.emoticon[data-ffz-emote="' + emote.id + '"] {' +
((emote.margins && ! emote.modifier) ? 'margin:' + emote.margins + ' !important;' : '') +
(emote.css || '') +
'}\n';
},

View file

@ -1045,6 +1045,8 @@ body.ffz-bttv-dark .ffz-ui-popup ul.menu svg path { fill: #d3d3d3; }
/* BTTV Menu Fixes */
.emote-menu .header-info img { max-width: 18px; max-height: 18px }
.bttv-incompatibility {
padding-top: 8px !important;
}
@ -1135,12 +1137,15 @@ body.ffz-bttv-dark .ffz-ui-popup .ffz-ui-menu-page { border-bottom: none }
.chatReplay .chat-messages .chat-line .mod-icons {
position: absolute;
z-index: 10;
left: 0; top: 2px; bottom: 2px;
padding: 4px 5px 4px 4px;
left: 0; top: 0; bottom: 0;
padding: 3px 5px 4px 4px;
background: rgba(255,255,255,0.8);
transition: margin-left .08s linear;
}
.chatReplay .show-mod-icons .chat-line .mod-icons { transition: none }
.chatReplay .chat-messages .chat-line:hover { overflow: visible }
.chatReplay .chat-messages .chat-line:hover .mod-icons {
margin-left: 0;
}
@ -3559,6 +3564,8 @@ body.ffz-bttv #ffz-feed-tabs .tabs { margin-bottom: 0 }
padding-top: 80px;
}
.cn-hosting .ffz.card__layout .card__title { color: #9c9c9c }
.cn-hosting .ffz.card__layout .card__title,
.ffz-channel-title-top .cn-metabar__more,
.app-main.theatre .cn-metabar__more {
@ -3750,11 +3757,21 @@ body:not(.ffz-channel-bar-bottom).ffz-small-player.ffz-minimal-channel-bar #play
/* Modifier Emotes */
.modified-emoticon {
position: relative;
.emoticon-grid span.emoticon:not([data-ffz-emote="59829"]) {
padding-top: 0;
margin: 0 !important
}
.modified-emoticon > .emoticon { margin: 0 }
.modified-emoticon ~ .emoticon { position: relative; z-index: 1}
.modified-emoticon {
position: relative;
z-index: 0;
}
.modified-emoticon[data-ffz-emote="59829"] span { right: 128px }
.modified-emoticon > img.emoticon { margin: 0 !important }
.modified-emoticon span {
position: absolute;