mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-07-25 12:08:30 +00:00
3.5.51 to 3.5.57. Changes to how chat history is implemented. Made the Actions and Metadata overlay for theater mode optional. Added support for the new Conversation UI. Increased socket server rollout. Mod cards update history in real time. Fixed global moderator badges. Refactored emote clicking code. Moved CSS to external again.
This commit is contained in:
parent
10da2b4fd5
commit
c40b3ba337
20 changed files with 459 additions and 2291 deletions
111
dark.css
111
dark.css
|
@ -164,6 +164,7 @@
|
|||
|
||||
/* Popups */
|
||||
|
||||
.ffz-dark .conversation-settings-menu,
|
||||
.ffz-dark .ember-chat .chat-interface .ffz-ui-popup.emoticon-selector .emoticon-selector-box,
|
||||
.ffz-dark .card,
|
||||
.ffz-dark #flyout .content,
|
||||
|
@ -926,3 +927,113 @@
|
|||
.ffz-dark .playlist-container:not(.playlist-enabled) .ui-sortable-helper {
|
||||
background-color: rgba(255,255,255,0.2);
|
||||
}
|
||||
|
||||
|
||||
/* Conversations */
|
||||
|
||||
.ffz-dark .conversation-settings-menu .options-divider {
|
||||
border-bottom-color: rgba(255,255,255,0.2);
|
||||
}
|
||||
|
||||
.ffz-dark .conversation-settings-menu:before {
|
||||
border-color: transparent;
|
||||
border-bottom-color: #32323e;
|
||||
}
|
||||
|
||||
.ffz-dark .conversation-settings-menu:after {
|
||||
border-color: transparent;
|
||||
border-bottom-color: rgb(16,16,16);
|
||||
}
|
||||
|
||||
.ffz-dark .conversations-list-icon {
|
||||
background: #19191f;
|
||||
color: #8c8c9c;
|
||||
border-color: #19191f
|
||||
}
|
||||
|
||||
.ffz-dark .conversations-list-icon:hover {
|
||||
color: #fff
|
||||
}
|
||||
|
||||
.ffz-dark .conversations-list {
|
||||
background: #19191f;
|
||||
border: 1px solid #32323e;
|
||||
color: #fff
|
||||
}
|
||||
|
||||
.ffz-dark .conversations-list:after {
|
||||
border-color: rgba(25,25,31,0);
|
||||
border-top-color: #19191f;
|
||||
border-width: 10px;
|
||||
margin-left: -10px
|
||||
}
|
||||
|
||||
.ffz-dark .conversations-list:before {
|
||||
right: 9px;
|
||||
border-color: rgba(50,50,62,0);
|
||||
border-top-color: #32323e
|
||||
}
|
||||
|
||||
.ffz-dark .conversations-list .conversations-list-header {
|
||||
background: #19191f;
|
||||
border-bottom: 1px solid #32323e;
|
||||
color: #fff
|
||||
}
|
||||
|
||||
.ffz-dark .conversations-list .conversation-preview-line {
|
||||
color: #8c8c9c
|
||||
}
|
||||
|
||||
.ffz-dark .conversations-list .conversations-list-item {
|
||||
border-bottom: 1px solid #32323e
|
||||
}
|
||||
|
||||
.ffz-dark .conversations-list .conversations-list-item:hover {
|
||||
background-color: #121217
|
||||
}
|
||||
|
||||
.ffz-dark .conversation-window {
|
||||
background: #19191f;
|
||||
box-shadow: none;
|
||||
color: #8c8c9c;
|
||||
}
|
||||
|
||||
.ffz-dark .conversations-list-icon,
|
||||
.ffz-dark .conversation-window {
|
||||
border: 1px solid rgba(255,255,255,0.2);
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.ffz-dark .conversation-header {
|
||||
background: #121217;
|
||||
box-shadow: none;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.2);
|
||||
}
|
||||
|
||||
.ffz-dark .conversation-input-bar textarea {
|
||||
border-color: rgba(255,255,255,0.1);
|
||||
background-color: rgba(255,255,255,0.05);
|
||||
color: #b6b6b6
|
||||
}
|
||||
|
||||
.ffz-dark .conversation-input-actions .button,
|
||||
.ffz-dark .conversation-input-actions .follow-button:not(.ember-follow) .follow {
|
||||
background-color: #444
|
||||
}
|
||||
|
||||
.ffz-dark .conversation-window.has-focus .conversation-header {
|
||||
background-color: #121217
|
||||
}
|
||||
|
||||
.ffz-dark .conversation-window.has-focus .conversation-header-name {
|
||||
color: #fff
|
||||
}
|
||||
|
||||
.ffz-dark .conversation-window.has-focus .conversation-input-bar textarea:focus {
|
||||
border-color: rgba(255,255,255,0.2)
|
||||
}
|
||||
|
||||
.ffz-dark .conversation-window.has-focus .conversation-input-actions .button,
|
||||
.ffz-dark .conversation-window.has-focus .conversation-input-actions .follow-button:not(.ember-follow) .follow {
|
||||
background-color: #6441a5
|
||||
}
|
|
@ -254,7 +254,7 @@ FFZ.prototype.render_badges = function(component, badges) {
|
|||
if ( ! this.settings.show_badges )
|
||||
return badges;
|
||||
|
||||
var user = component.get('msgObject.from'),
|
||||
var user = component.get('msgObject.from') || component.get('message.from.username'),
|
||||
room_id = component.get('msgObject.room') || App.__container__.lookup('controller:chat').get('currentRoom.id');
|
||||
|
||||
var data = this.users[user];
|
||||
|
|
|
@ -581,6 +581,18 @@ FFZ.prototype._update_colors = function(darkness_only) {
|
|||
|
||||
bit.style.color = is_dark ? colors[1] : colors[0];
|
||||
}
|
||||
|
||||
colored_bits = document.querySelectorAll('.conversation-chat-line .has-color');
|
||||
for(var i=0, l=colored_bits.length; i < l; i++) {
|
||||
var bit = colored_bits[i],
|
||||
color = bit.getAttribute('data-color'),
|
||||
colors = color && this._handle_color(color);
|
||||
|
||||
if ( ! colors )
|
||||
continue;
|
||||
|
||||
bit.style.color = is_dark ? colors[1] : colors[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2,10 +2,13 @@ var SVGPATH = '<path d="m120.95 1.74c4.08-0.09 8.33-0.84 12.21 0.82 3.61 1.8 7 4
|
|||
|
||||
DEBUG = localStorage.ffzDebugMode == "true" && document.body.classList.contains('ffz-dev'),
|
||||
SERVER = DEBUG ? "//localhost:8000/" : "//cdn.frankerfacez.com/";
|
||||
DIRECT_SERVER = DEBUG ? "//localhost:8000/" : "//direct-cdn.frankerfacez.com/";
|
||||
|
||||
module.exports = {
|
||||
DEBUG: DEBUG,
|
||||
SERVER: SERVER,
|
||||
DIRECT_SERVER: DIRECT_SERVER,
|
||||
|
||||
API_SERVER: "//api.frankerfacez.com/",
|
||||
API_SERVER_2: "//direct-api.frankerfacez.com/",
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ FFZ.prototype.setup_channel = function() {
|
|||
|
||||
// Settings stuff!
|
||||
document.body.classList.toggle("ffz-hide-view-count", !this.settings.channel_views);
|
||||
document.body.classList.toggle('ffz-theater-stats', this.settings.theater_stats);
|
||||
|
||||
this.log("Creating channel style element.");
|
||||
var s = this._channel_style = document.createElement('style');
|
||||
|
@ -790,6 +791,20 @@ FFZ.settings_info.stream_title = {
|
|||
};
|
||||
|
||||
|
||||
FFZ.settings_info.theater_stats = {
|
||||
type: "boolean",
|
||||
value: true,
|
||||
no_mobile: true,
|
||||
|
||||
category: "Channel Metadata",
|
||||
name: "Display on Theater Mode Hover",
|
||||
help: "Show the channel metadata and actions over the video player in theater mode when you hover it with your mouse.",
|
||||
on_update: function(val) {
|
||||
document.body.classList.toggle('ffz-theater-stats', val);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
FFZ.basic_settings.channel_info = {
|
||||
type: "select",
|
||||
options: {
|
||||
|
|
|
@ -280,6 +280,20 @@ FFZ.settings_info.group_tabs = {
|
|||
};
|
||||
|
||||
|
||||
FFZ.settings_info.top_conversations = {
|
||||
type: "boolean",
|
||||
value: false,
|
||||
no_mobile: true,
|
||||
|
||||
category: "Chat Appearance",
|
||||
name: "Conversations on Top",
|
||||
help: "Display the new conversation-style whisper UI at the top of the window instead of the bottom.",
|
||||
on_update: function(val) {
|
||||
document.body.classList.toggle('ffz-top-conversations', val);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
FFZ.settings_info.pinned_rooms = {
|
||||
value: [],
|
||||
visible: false,
|
||||
|
@ -298,6 +312,7 @@ FFZ.settings_info.visible_rooms = {
|
|||
FFZ.prototype.setup_chatview = function() {
|
||||
document.body.classList.toggle("ffz-minimal-chat-head", this.settings.minimal_chat === 1 || this.settings.minimal_chat === 3);
|
||||
document.body.classList.toggle("ffz-minimal-chat-input", this.settings.minimal_chat === 2 || this.settings.minimal_chat === 3);
|
||||
document.body.classList.toggle('ffz-top-conversations', this.settings.top_conversations);
|
||||
|
||||
this.log("Hooking the Ember Chat controller.");
|
||||
|
||||
|
|
|
@ -30,45 +30,44 @@ FFZ.prototype.setup_directory = function() {
|
|||
if ( ChannelView )
|
||||
this._modify_directory_live(ChannelView);
|
||||
|
||||
var CreativeChannel = App.__container__.resolve('view:creative-channel');
|
||||
if ( CreativeChannel )
|
||||
this._modify_directory_live(CreativeChannel);
|
||||
|
||||
var CSGOChannel = App.__container__.resolve('view:cs-go-channel');
|
||||
if ( CSGOChannel )
|
||||
this._modify_directory_live(CSGOChannel, true);
|
||||
|
||||
var HostView = App.__container__.resolve('view:host');
|
||||
if ( HostView )
|
||||
this._modify_directory_host(HostView);
|
||||
|
||||
var VideoView = App.__container__.resolve('view:video');
|
||||
if ( VideoView )
|
||||
this._modify_directory_video(VideoView);
|
||||
|
||||
// TODO: Process existing views.
|
||||
}
|
||||
|
||||
|
||||
FFZ.prototype._modify_directory_video = function(dir) {
|
||||
var f = this;
|
||||
dir.reopen({
|
||||
didInsertElement: function() {
|
||||
this._super();
|
||||
// Initialize existing views.
|
||||
for(var key in Ember.View.views) {
|
||||
var view = Ember.View.views[key];
|
||||
if ( view instanceof ChannelView || view instanceof CreativeChannel || view instanceof CSGOChannel || view instanceof HostView )
|
||||
view.ffzInit();
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
dir.create().destroy();
|
||||
} catch(err) { }
|
||||
}
|
||||
|
||||
|
||||
FFZ.prototype._modify_directory_live = function(dir) {
|
||||
FFZ.prototype._modify_directory_live = function(dir, is_csgo) {
|
||||
var f = this;
|
||||
dir.reopen({
|
||||
didInsertElement: function() {
|
||||
this._super();
|
||||
this.ffzInit();
|
||||
},
|
||||
|
||||
ffzInit: function() {
|
||||
var el = this.get('element'),
|
||||
meta = el && el.querySelector('.meta'),
|
||||
thumb = el && el.querySelector('.thumb'),
|
||||
cap = thumb && thumb.querySelector('.cap');
|
||||
|
||||
|
||||
if ( f.settings.stream_uptime && f.settings.stream_uptime < 3 && cap ) {
|
||||
// CSGO doesn't provide the actual uptime information...
|
||||
if ( !is_csgo && f.settings.stream_uptime && f.settings.stream_uptime < 3 && cap ) {
|
||||
var t_el = this._ffz_uptime = document.createElement('div');
|
||||
t_el.className = 'overlay_info length live';
|
||||
|
||||
|
@ -88,6 +87,8 @@ FFZ.prototype._modify_directory_live = function(dir) {
|
|||
target = this.get('context.model.channel.name');
|
||||
|
||||
logo.className = 'profile-photo';
|
||||
logo.classList.toggle('is-csgo', is_csgo);
|
||||
|
||||
logo.src = this.get('context.model.channel.logo') || "http://static-cdn.jtvnw.net/jtv_user_pictures/xarth/404_user_150x150.png";
|
||||
logo.alt = this.get('context.model.channel.display_name');
|
||||
|
||||
|
|
|
@ -47,6 +47,12 @@ FFZ.settings_info.portrait_mode = {
|
|||
}
|
||||
}
|
||||
|
||||
FFZ.settings_info.portrait_warning = {
|
||||
value: false,
|
||||
visible: false
|
||||
}
|
||||
|
||||
|
||||
FFZ.settings_info.swap_sidebars = {
|
||||
type: "boolean",
|
||||
value: false,
|
||||
|
@ -177,7 +183,7 @@ FFZ.prototype.setup_layout = function() {
|
|||
height = size[1];
|
||||
|
||||
// Make sure we have at least a bit of room for the chat.
|
||||
return this.get("windowHeight") < (height + 120 + 60 + 100);
|
||||
return this.get("windowHeight") < (height + 120 + 60 + 200);
|
||||
|
||||
} else
|
||||
return this.get("windowWidth") < (1090 - this.get('rightColumnWidth'))
|
||||
|
@ -217,27 +223,14 @@ FFZ.prototype.setup_layout = function() {
|
|||
return "<style>.dynamic-player, .dynamic-player object, .dynamic-player video{width:" + width + "px !important;height:" + height + "px !important} .dynamic-target-player,.dynamic-target-player object, .dynamic-target-player video{width:" + width + "px !important;height:" + host_height + "px !important}</style><style>.dynamic-player .player object{width:100% !important; height:100% !important}</style>";
|
||||
}.property("playerSize"),
|
||||
|
||||
/*ffzUpdateWidth: _.throttle(function() {
|
||||
var rc = document.querySelector('#right_close');
|
||||
if ( ! rc )
|
||||
ffzPortraitWarning: function() {
|
||||
if ( ! f.settings.portrait_mode || f._portrait_warning || f.settings.portrait_warning || ! this.get('isTooSmallForRightColumn') )
|
||||
return;
|
||||
|
||||
var left_width = this.get("isLeftColumnClosed") ? 50 : 240,
|
||||
right_width;
|
||||
f._portrait_warning = true;
|
||||
f.show_message('Twitch\'s Chat Sidebar has been hidden as a result of FrankerFaceZ\'s Portrait Mode because the window is too wide.<br><br>Please <a href="#" onclick="ffz.settings.set(\'portrait_mode\',0);jQuery(this).parents(\'.ffz-noty\').remove();ffz._portrait_warning = false;return false">disable Portrait Mode</a> or make your window narrower.<br><br><a href="#" onclick="onclick="ffz.settings.set(\'portrait_warning\',true);jQuery(this).parents(\'.ffz-noty\').remove();return false">Do not show this message again</a>');
|
||||
|
||||
if ( f.settings.swap_sidebars )
|
||||
right_width = rc.offsetLeft; // + this.get('rightColumnWidth') - 5;
|
||||
else
|
||||
right_width = document.body.offsetWidth - rc.offsetLeft - left_width - 25;
|
||||
|
||||
if ( right_width < 250 ) {
|
||||
// Close it!
|
||||
|
||||
}
|
||||
|
||||
this.set('rightColumnWidth', right_width);
|
||||
Ember.propertyDidChange(Layout, 'contentWidth');
|
||||
}, 200),*/
|
||||
}.observes("isTooSmallForRightColumn"),
|
||||
|
||||
ffzUpdateCss: function() {
|
||||
// TODO: Fix this mess of duplicate code.
|
||||
|
@ -332,6 +325,6 @@ FFZ.prototype.setup_layout = function() {
|
|||
Layout.set('rawPortraitMode', this.settings.portrait_mode);
|
||||
|
||||
// Force re-calculation of everything.
|
||||
Ember.propertyDidChange(Layout, 'contentWidth');
|
||||
Ember.propertyDidChange(Layout, 'windowWidth');
|
||||
Ember.propertyDidChange(Layout, 'windowHeight');
|
||||
}
|
|
@ -555,6 +555,13 @@ FFZ.prototype.setup_line = function() {
|
|||
if ( Line )
|
||||
this._modify_line(Line);
|
||||
|
||||
this.log("Hooking the Ember Conversation Line component.");
|
||||
var Conversation = App.__container__.resolve('component:conversation-line');
|
||||
|
||||
if ( Conversation )
|
||||
this._modify_conversation_line(Conversation);
|
||||
|
||||
|
||||
// Store the capitalization of our own name.
|
||||
var user = this.get_user();
|
||||
if ( user && user.name )
|
||||
|
@ -568,6 +575,67 @@ FFZ.prototype.save_aliases = function() {
|
|||
}
|
||||
|
||||
|
||||
FFZ.prototype._modify_conversation_line = function(component) {
|
||||
var f = this,
|
||||
|
||||
Layout = App.__container__.lookup('controller:layout'),
|
||||
Settings = App.__container__.lookup('controller:settings');
|
||||
|
||||
component.reopen({
|
||||
tokenizedMessage: function() {
|
||||
try {
|
||||
return f.tokenize_conversation_line(this.get('message'));
|
||||
} catch(err) {
|
||||
f.error("convo-line tokenizedMessage: " + err);
|
||||
return this._super();
|
||||
}
|
||||
|
||||
}.property("message", "currentUsername"),
|
||||
|
||||
click: function(e) {
|
||||
if ( e.target && e.target.classList.contains('deleted-link') )
|
||||
return f._deleted_link_click.bind(e.target)(e);
|
||||
|
||||
if ( f._click_emote(e.target, e) )
|
||||
return;
|
||||
|
||||
return this._super(e);
|
||||
},
|
||||
|
||||
render: function(e) {
|
||||
var user = this.get('message.from.username'),
|
||||
raw_color = this.get('message.from.color'),
|
||||
colors = raw_color && f._handle_color(raw_color),
|
||||
|
||||
is_dark = (Layout && Layout.get('isTheatreMode')) || f.settings.dark_twitch;
|
||||
|
||||
e.push('<div class="indicator"></div>');
|
||||
|
||||
var alias = f.aliases[user],
|
||||
name = this.get('message.from.displayName') || (user && user.capitalize()) || "unknown user",
|
||||
style = colors && 'color:' + (is_dark ? colors[1] : colors[0]),
|
||||
colored = style ? ' has-color' : '';
|
||||
|
||||
if ( alias )
|
||||
e.push('<span class="from ffz-alias tooltip' + colored + '" style="' + style + (colors ? '" data-colors="' + raw_color : '') + '" title="' + utils.sanitize(name) + '">' + utils.sanitize(alias) + '</span>');
|
||||
else
|
||||
e.push('<span class="from' + colored + '" style="' + style + (colors ? '" data-color="' + raw_color : '') + '">' + utils.sanitize(name) + '</span>');
|
||||
|
||||
e.push('<span class="colon">:</span> ');
|
||||
|
||||
if ( ! this.get('isActionMessage') ) {
|
||||
style = '';
|
||||
colored = '';
|
||||
}
|
||||
|
||||
e.push('<span class="message' + colored + '" style="' + style + (colors ? '" data-color="' + raw_color : '') + '">');
|
||||
e.push(f.render_tokens(this.get('tokenizedMessage'), true));
|
||||
e.push('</span>');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
FFZ.prototype._modify_line = function(component) {
|
||||
var f = this,
|
||||
|
||||
|
@ -577,45 +645,12 @@ FFZ.prototype._modify_line = function(component) {
|
|||
|
||||
component.reopen({
|
||||
tokenizedMessage: function() {
|
||||
// Add our own step to the tokenization procedure.
|
||||
var tokens = this.get("msgObject.cachedTokens");
|
||||
if ( tokens )
|
||||
return tokens;
|
||||
|
||||
tokens = this._super();
|
||||
|
||||
var start = performance.now(),
|
||||
user = f.get_user(),
|
||||
from_me = user && this.get("msgObject.from") === user.login;
|
||||
|
||||
tokens = f._remove_banned(tokens);
|
||||
tokens = f._emoticonize(this, tokens);
|
||||
|
||||
if ( f.settings.parse_emoji )
|
||||
tokens = f.tokenize_emoji(tokens);
|
||||
|
||||
// Store the capitalization.
|
||||
var display = this.get("msgObject.tags.display-name");
|
||||
if ( display && display.length )
|
||||
FFZ.capitalization[this.get("msgObject.from")] = [display.trim(), Date.now()];
|
||||
|
||||
if ( ! from_me )
|
||||
tokens = f.tokenize_mentions(tokens);
|
||||
|
||||
for(var i = 0; i < tokens.length; i++) {
|
||||
var token = tokens[i];
|
||||
if ( ! _.isString(token) && token.mentionedUser && ! token.own ) {
|
||||
this.set('msgObject.ffz_has_mention', true);
|
||||
break;
|
||||
try {
|
||||
return f.tokenize_chat_line(this.get('msgObject'));
|
||||
} catch(err) {
|
||||
f.error("chat-line tokenizedMessage: " + err);
|
||||
return this._super();
|
||||
}
|
||||
}
|
||||
|
||||
var end = performance.now();
|
||||
if ( end - start > 5 )
|
||||
f.log("Tokenizing Message Took Too Long - " + (end-start) + "ms", tokens, false, true);
|
||||
|
||||
this.set("msgObject.cachedTokens", tokens);
|
||||
return tokens;
|
||||
|
||||
}.property("msgObject.message", "isChannelLinksDisabled", "currentUserNick", "msgObject.from", "msgObject.tags.emotes"),
|
||||
|
||||
|
@ -633,18 +668,6 @@ FFZ.prototype._modify_line = function(component) {
|
|||
if ( e.target && e.target.classList.contains('mod-icon') ) {
|
||||
jQuery(e.target).trigger('mouseout');
|
||||
|
||||
/*if ( e.target.classList.contains('purge') ) {
|
||||
var i = this.get('msgObject.from'),
|
||||
room_id = this.get('msgObject.room'),
|
||||
room = room_id && f.rooms[room_id] && f.rooms[room_id].room;
|
||||
|
||||
if ( room ) {
|
||||
room.send("/timeout " + i + " 1", true);
|
||||
room.clearMessages(i);
|
||||
}
|
||||
return;
|
||||
}*/
|
||||
|
||||
if ( e.target.classList.contains('custom') ) {
|
||||
var room_id = this.get('msgObject.room'),
|
||||
room = room_id && f.rooms[room_id] && f.rooms[room_id].room,
|
||||
|
@ -660,31 +683,9 @@ FFZ.prototype._modify_line = function(component) {
|
|||
}
|
||||
}
|
||||
|
||||
if ( (e.shiftKey || e.shiftLeft) && f.settings.clickable_emoticons && e.target && e.target.classList.contains('emoticon') ) {
|
||||
var eid = e.target.getAttribute('data-emote');
|
||||
if ( eid )
|
||||
window.open("https://twitchemotes.com/emote/" + eid);
|
||||
else {
|
||||
eid = e.target.getAttribute("data-ffz-emote");
|
||||
var es = e.target.getAttribute("data-ffz-set"),
|
||||
set = es && f.emote_sets[es],
|
||||
url;
|
||||
|
||||
if ( ! set )
|
||||
if ( f._click_emote(e.target, e) )
|
||||
return;
|
||||
|
||||
if ( set.hasOwnProperty('source_ext') ) {
|
||||
var api = f._apis[set.source_ext];
|
||||
if ( api && api.emote_url_generator )
|
||||
url = api.emote_url_generator(set.source_id, eid);
|
||||
} else
|
||||
url = "https://www.frankerfacez.com/emoticons/" + eid;
|
||||
|
||||
if ( url )
|
||||
window.open(url);
|
||||
}
|
||||
}
|
||||
|
||||
return this._super(e);
|
||||
},
|
||||
|
||||
|
@ -768,7 +769,7 @@ FFZ.prototype._modify_line = function(component) {
|
|||
else if ( this.get('isAdmin') )
|
||||
badges[0] = {klass: 'admin', title: 'Admin'};
|
||||
else if ( this.get('isGlobalMod') )
|
||||
badges[0] = {klass: 'global-mod', title: 'Global Moderator'};
|
||||
badges[0] = {klass: 'global-moderator', title: 'Global Moderator'};
|
||||
else if ( ! is_whisper && this.get('isModerator') )
|
||||
badges[0] = {klass: 'moderator', title: 'Moderator'};
|
||||
|
||||
|
@ -835,7 +836,7 @@ FFZ.prototype._modify_line = function(component) {
|
|||
if ( deleted )
|
||||
e.push('<span class="deleted"><a class="undelete" href="#"><message deleted></a></span>');
|
||||
else {
|
||||
e.push('<span class="message' + colored + '" style="' + style + '">');
|
||||
e.push('<span class="message' + colored + '" style="' + style + (colors ? '" data-color="' + raw_color : '') + '">');
|
||||
e.push(f.render_tokens(this.get('tokenizedMessage'), true));
|
||||
|
||||
var old_messages = this.get('msgObject.ffz_old_messages');
|
||||
|
|
|
@ -435,13 +435,20 @@ FFZ.prototype.setup_mod_card = function() {
|
|||
return alias || this.get("cardInfo.user.display_name") || user_id.capitalize();
|
||||
}),
|
||||
|
||||
willDestroy: function() {
|
||||
if ( f._mod_card === this )
|
||||
f._mod_card = undefined;
|
||||
this._super();
|
||||
},
|
||||
|
||||
didInsertElement: function() {
|
||||
this._super();
|
||||
window._card = this;
|
||||
try {
|
||||
if ( f.has_bttv )
|
||||
return;
|
||||
|
||||
f._mod_card = this;
|
||||
|
||||
var el = this.get('element'),
|
||||
controller = this.get('controller'),
|
||||
line,
|
||||
|
@ -450,11 +457,14 @@ FFZ.prototype.setup_mod_card = function() {
|
|||
|
||||
chat = window.App && App.__container__.lookup('controller:chat'),
|
||||
user = f.get_user(),
|
||||
is_broadcaster = user && chat && chat.get('currentRoom.id') === user.login,
|
||||
room_id = chat && chat.get('currentRoom.id'),
|
||||
is_broadcaster = user && room_id === user.login,
|
||||
|
||||
user_id = controller.get('cardInfo.user.id'),
|
||||
alias = f.aliases[user_id];
|
||||
|
||||
this.ffz_room_id = room_id;
|
||||
|
||||
// Alias Display
|
||||
if ( alias ) {
|
||||
var name = el.querySelector('h3.name'),
|
||||
|
@ -735,17 +745,19 @@ FFZ.prototype.setup_mod_card = function() {
|
|||
|
||||
l_el.innerHTML = (helpers ? '<span class="timestamp float-left">' + helpers.getTime(line.date) + '</span> ' : '') + '<span class="message">' + (line.style === 'action' ? '*' + line.from + ' ' : '') + f.render_tokens(line.cachedTokens) + '</span>';
|
||||
|
||||
// Banned Links
|
||||
var bad_links = l_el.querySelectorAll('a.deleted-link');
|
||||
for(var x=0; x < bad_links.length; x++)
|
||||
bad_links[x].addEventListener("click", f._deleted_link_click);
|
||||
|
||||
// Interactivity
|
||||
jQuery('a.deleted-link', l_el).click(f._deleted_link_click);
|
||||
jQuery('img.emoticon', l_el).click(function(e) { f._click_emote(this, e) });
|
||||
jQuery('.html-tooltip', l_el).tipsy({html:true});
|
||||
|
||||
// Append
|
||||
history.appendChild(l_el);
|
||||
}
|
||||
|
||||
el.appendChild(history);
|
||||
|
||||
this.ffz_alternate = alternate;
|
||||
|
||||
// Lazy scroll-to-bottom
|
||||
history.scrollTop = history.scrollHeight;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ var FFZ = window.FrankerFaceZ,
|
|||
HOSTED_SUB = / subscribed to /,
|
||||
constants = require('../constants'),
|
||||
utils = require('../utils'),
|
||||
helpers,
|
||||
|
||||
// StrimBagZ Support
|
||||
is_android = navigator.userAgent.indexOf('Android') !== -1,
|
||||
|
@ -14,7 +15,12 @@ var FFZ = window.FrankerFaceZ,
|
|||
return "";
|
||||
|
||||
return '.chat-line[data-room="' + room.id + '"] .badges .moderator:not(.ffz-badge-replacement) { background-image:url("' + room.moderator_badge + '") !important; }';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
try {
|
||||
helpers = window.require && window.require("ember-twitch-chat/helpers/chat-line-helpers");
|
||||
} catch(err) { }
|
||||
|
||||
|
||||
// --------------------
|
||||
|
@ -723,10 +729,11 @@ FFZ.prototype._insert_history = function(room_id, data) {
|
|||
tmiRoom = r.tmiRoom,
|
||||
|
||||
inserted = 0,
|
||||
purged = {},
|
||||
|
||||
last_msg = data[data.length - 1],
|
||||
now = new Date(),
|
||||
last_date = typeof last_msg.date === "string" ? utils.parse_date(last_msg.date) : last_msg.date,
|
||||
last_date = (typeof last_msg.date === "string" || typeof last_msg.date === "number") ? (last_msg.date = utils.parse_date(last_msg.date)) : last_msg.date,
|
||||
age = (now - last_date) / 1000,
|
||||
is_old = age > 300,
|
||||
|
||||
|
@ -738,9 +745,13 @@ FFZ.prototype._insert_history = function(room_id, data) {
|
|||
|
||||
var i = data.length;
|
||||
while(i--) {
|
||||
var msg = data[i];
|
||||
var msg = data[i],
|
||||
is_deleted = msg.ffz_deleted = purged[msg.from] || false;
|
||||
|
||||
if ( typeof msg.date === "string" )
|
||||
if ( is_deleted && ! this.settings.prevent_clear )
|
||||
msg.deleted = true;
|
||||
|
||||
if ( typeof msg.date === "string" || typeof msg.date === "number" )
|
||||
msg.date = utils.parse_date(msg.date);
|
||||
|
||||
msg.ffz_alternate = alternation = ! alternation;
|
||||
|
@ -774,6 +785,14 @@ FFZ.prototype._insert_history = function(room_id, data) {
|
|||
msg.style = "notification";
|
||||
}
|
||||
|
||||
if ( msg.tags && typeof msg.tags.emotes === "string" )
|
||||
try {
|
||||
msg.tags.emotes = JSON.parse(msg.tags.emotes);
|
||||
} catch(err) {
|
||||
f.log("Error Parsing JSON Emotes: " + err);
|
||||
msg.tags.emotes = {};
|
||||
}
|
||||
|
||||
if ( ! msg.cachedTokens || ! msg.cachedTokens.length )
|
||||
this.tokenize_chat_line(msg, true, r.get('roomProperties.hide_chat_links'));
|
||||
|
||||
|
@ -791,6 +810,14 @@ FFZ.prototype._insert_history = function(room_id, data) {
|
|||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
// If there was a CLEARCHAT, stop processing.
|
||||
if ( msg.tags && msg.tags.target === '@@' )
|
||||
break;
|
||||
|
||||
// If there was a purge, just track the name.
|
||||
else if ( msg.tags && msg.tags.target )
|
||||
purged[msg.tags.target] = true;
|
||||
}
|
||||
|
||||
if ( is_old ) {
|
||||
|
@ -1190,6 +1217,38 @@ FFZ.prototype._modify_room = function(room) {
|
|||
|
||||
if ( user_history.length > 20 )
|
||||
user_history.shift();
|
||||
|
||||
if ( f._mod_card && f._mod_card.ffz_room_id === msg.room && f._mod_card.get('cardInfo.user.id') === msg.from ) {
|
||||
var el = f._mod_card.get('element'),
|
||||
history = el && el.querySelector('.chat-history'),
|
||||
was_at_top = history && history.scrollTop >= (history.scrollHeight - history.clientHeight);
|
||||
|
||||
if ( history ) {
|
||||
var l_el = document.createElement('li');
|
||||
l_el.className = 'message-line chat-line clearfix';
|
||||
|
||||
l_el.classList.toggle('ffz-alternate', f._mod_card.ffz_alternate);
|
||||
f._mod_card.ffz_alternate = !f._mod_card.ffz_alternate;
|
||||
|
||||
if ( msg.style )
|
||||
l_el.classList.add(msg.style);
|
||||
|
||||
l_el.innerHTML = (helpers ? '<span class="timestamp float-left">' + helpers.getTime(msg.date) + '</span> ' : '') + '<span class="message">' + (msg.style === 'action' ? '*' + msg.from + ' ' : '') + f.render_tokens(msg.cachedTokens) + '</span>';
|
||||
|
||||
// Interactivity
|
||||
jQuery('a.deleted-link', l_el).click(f._deleted_link_click);
|
||||
jQuery('img.emoticon', l_el).click(function(e) { f._click_emote(this, e) });
|
||||
jQuery('.html-tooltip', l_el).tipsy({html:true});
|
||||
|
||||
history.appendChild(l_el);
|
||||
if ( was_at_top )
|
||||
setTimeout(function() { history.scrollTop = history.scrollHeight; })
|
||||
|
||||
// Don't do infinite scrollback.
|
||||
if ( history.childElementCount > 50 )
|
||||
history.removeChild(history.firstElementChild);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -141,6 +141,41 @@ FFZ.prototype._report_emotes = function() {
|
|||
}
|
||||
|
||||
|
||||
// ------------------------
|
||||
// Emote Click Handler
|
||||
// ------------------------
|
||||
|
||||
FFZ.prototype._click_emote = function(target, event) {
|
||||
if ( ! this.settings.clickable_emoticons || (event && !((event.shiftKey || event.shiftLeft) && target && target.classList.contains('emoticon'))) )
|
||||
return;
|
||||
|
||||
var eid = target.getAttribute('data-emote');
|
||||
if ( eid )
|
||||
window.open("https://twitchemotes.com/emote/" + eid);
|
||||
else {
|
||||
eid = target.getAttribute("data-ffz-emote");
|
||||
var es = target.getAttribute("data-ffz-set"),
|
||||
emote_set = es && this.emote_sets[es],
|
||||
url;
|
||||
|
||||
if ( ! emote_set )
|
||||
return;
|
||||
|
||||
if ( emote_set.hasOwnProperty('source_ext') ) {
|
||||
var api = this._apis[emote_set.source_ext];
|
||||
if ( api && api.emote_url_generator )
|
||||
url = api.emote_url_generator(emote_set.source_id, eid);
|
||||
} else
|
||||
url = "https://www.frankerfacez.com/emoticons/" + eid;
|
||||
|
||||
if ( url ) {
|
||||
window.open(url);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------
|
||||
// Twitch Emoticon Checker
|
||||
// ------------------------
|
||||
|
|
|
@ -22,7 +22,7 @@ FFZ.get = function() { return FFZ.instance; }
|
|||
|
||||
// Version
|
||||
var VER = FFZ.version_info = {
|
||||
major: 3, minor: 5, revision: 50,
|
||||
major: 3, minor: 5, revision: 57,
|
||||
toString: function() {
|
||||
return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || "");
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ FFZ.settings_info.socket_server_pool = {
|
|||
2: "Development"
|
||||
},
|
||||
|
||||
value: ffz_socket_seed > 0.65 ? 1 : 0,
|
||||
value: ffz_socket_seed > 0.4 ? 1 : 0,
|
||||
|
||||
process_value: function(val) {
|
||||
if ( typeof val === "string" )
|
||||
|
|
2146
src/styles/style.css
2146
src/styles/style.css
File diff suppressed because it is too large
Load diff
|
@ -401,14 +401,58 @@ FFZ.prototype.load_twitch_emote_data = function(tries) {
|
|||
// Tokenization
|
||||
// ---------------------
|
||||
|
||||
FFZ.prototype.tokenize_conversation_line = function(message, prevent_notification) {
|
||||
var msg = message.get('body'),
|
||||
user = this.get_user(),
|
||||
from_user = message.get('from.username'),
|
||||
from_me = user && from_user === user.login,
|
||||
|
||||
emotes = message.get('tags.emotes'),
|
||||
tokens = [msg];
|
||||
|
||||
// Standard Tokenization
|
||||
if ( helpers && helpers.linkifyMessage )
|
||||
tokens = helpers.linkifyMessage(tokens);
|
||||
|
||||
if ( user && user.login && helpers && helpers.mentionizeMessage )
|
||||
tokens = helpers.mentionizeMessage(tokens, user.login, from_me);
|
||||
|
||||
if ( helpers && helpers.emoticonizeMessage && emotes )
|
||||
tokens = helpers.emoticonizeMessage(tokens, emotes);
|
||||
|
||||
if ( this.settings.replace_bad_emotes )
|
||||
tokens = this.tokenize_replace_emotes(tokens);
|
||||
|
||||
// FrankerFaceZ Extras
|
||||
tokens = this._remove_banned(tokens);
|
||||
tokens = this.tokenize_emotes(from_user, undefined, tokens, from_me);
|
||||
|
||||
if ( this.settings.parse_emoji )
|
||||
tokens = this.tokenize_emoji(tokens);
|
||||
|
||||
// Capitalization
|
||||
var display_name = message.get('from.displayName');
|
||||
if ( display_name && display_name.length )
|
||||
FFZ.capitalization[from_user] = [display_name.trim(), Date.now()];
|
||||
|
||||
// Mentions!
|
||||
if ( ! from_me )
|
||||
tokens = this.tokenize_mentions(tokens);
|
||||
|
||||
// TODO: Notifications?
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
FFZ.prototype.tokenize_chat_line = function(msgObject, prevent_notification, delete_links) {
|
||||
if ( msgObject.cachedTokens )
|
||||
return msgObject.cachedTokens;
|
||||
|
||||
var msg = msgObject.message,
|
||||
var msg = msgObject.message || msgObject.get('body'),
|
||||
user = this.get_user(),
|
||||
room_id = msgObject.room,
|
||||
from_me = user && msgObject.from === user.login,
|
||||
from_user = msgObject.from,
|
||||
from_me = user && from_user === user.login,
|
||||
emotes = msgObject.tags && msgObject.tags.emotes,
|
||||
|
||||
tokens = [msg];
|
||||
|
@ -438,7 +482,7 @@ FFZ.prototype.tokenize_chat_line = function(msgObject, prevent_notification, del
|
|||
|
||||
// FrankerFaceZ Extras
|
||||
tokens = this._remove_banned(tokens);
|
||||
tokens = this.tokenize_emotes(msgObject.from, room_id, tokens, from_me);
|
||||
tokens = this.tokenize_emotes(from_user, room_id, tokens, from_me);
|
||||
|
||||
if ( this.settings.parse_emoji )
|
||||
tokens = this.tokenize_emoji(tokens);
|
||||
|
@ -446,7 +490,7 @@ FFZ.prototype.tokenize_chat_line = function(msgObject, prevent_notification, del
|
|||
// Capitalization
|
||||
var display = msgObject.tags && msgObject.tags['display-name'];
|
||||
if ( display && display.length )
|
||||
FFZ.capitalization[msgObject.from] = [display.trim(), Date.now()];
|
||||
FFZ.capitalization[from_user] = [display.trim(), Date.now()];
|
||||
|
||||
|
||||
// Mentions!
|
||||
|
@ -482,7 +526,7 @@ FFZ.prototype.tokenize_chat_line = function(msgObject, prevent_notification, del
|
|||
else
|
||||
room_name = FFZ.get_capitalization(room_id);
|
||||
|
||||
display = display || Twitch.display.capitalize(msgObject.from);
|
||||
display = display || Twitch.display.capitalize(from_user);
|
||||
|
||||
if ( msgObject.style === 'action' )
|
||||
msg = '* ' + display + ' ' + msg;
|
||||
|
@ -602,7 +646,7 @@ FFZ.prototype.render_tokens = function(tokens, render_links) {
|
|||
|
||||
var mirror_url = utils.quote_attr(constants.EMOTE_MIRROR_BASE + id + '.png');
|
||||
|
||||
extra = ' data-emote="' + id + '" onerror="FrankerFaceZ._emote_mirror_swap(this)"';
|
||||
extra = ' data-emote="' + id + '"'; // onerror="FrankerFaceZ._emote_mirror_swap(this)"'; // Disable error checking for now.
|
||||
|
||||
if ( ! constants.EMOTE_REPLACEMENTS[id] )
|
||||
srcset = build_srcset(id);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
var FFZ = window.FrankerFaceZ,
|
||||
constants = require("../constants"),
|
||||
styles = require("../styles");
|
||||
constants = require("../constants");
|
||||
//styles = require("../styles");
|
||||
|
||||
|
||||
// ---------------------
|
||||
|
@ -211,7 +211,6 @@ FFZ.prototype._load_dark_css = function() {
|
|||
|
||||
s.id = "ffz-dark-css";
|
||||
s.setAttribute('rel', 'stylesheet');
|
||||
s.setAttribute('href', constants.SERVER + "script/dark.css?_=" + (constants.DEBUG ? Date.now() : FFZ.version_info));
|
||||
s.onerror = "this.href = this.href + '_';"
|
||||
s.setAttribute('href', constants.DIRECT_SERVER + "script/dark.css?_=" + (constants.DEBUG ? Date.now() : FFZ.version_info));
|
||||
document.head.appendChild(s);
|
||||
}
|
|
@ -181,6 +181,11 @@ FFZ.prototype.show_notification = function(message, title, tag, timeout, on_clic
|
|||
// ---------------------
|
||||
|
||||
FFZ.prototype.show_message = function(message) {
|
||||
if ( ! window.jQuery || ! window.jQuery.noty || ! jQuery.noty.themes.ffzTheme ) {
|
||||
setTimeout(this.show_message.bind(this, message), 50);
|
||||
return;
|
||||
}
|
||||
|
||||
window.noty({
|
||||
text: message,
|
||||
theme: "ffzTheme",
|
||||
|
|
|
@ -1,18 +1,24 @@
|
|||
var FFZ = window.FrankerFaceZ,
|
||||
constants = require('../constants'),
|
||||
styles = require('../styles');
|
||||
constants = require('../constants');
|
||||
//styles = require('../styles');
|
||||
|
||||
FFZ.prototype.setup_css = function() {
|
||||
document.body.classList.toggle('ffz-flip-dashboard', this.settings.flip_dashboard);
|
||||
|
||||
this.log("Injecting main FrankerFaceZ CSS.");
|
||||
|
||||
var s = this._main_style = document.createElement('style');
|
||||
var s = this._main_style = document.createElement('link');
|
||||
s.id = "ffz-main-css";
|
||||
s.setAttribute('rel', 'stylesheet');
|
||||
s.setAttribute('href', constants.DIRECT_SERVER + "script/style.css?_=" + (constants.DEBUG ? Date.now() : FFZ.version_info));
|
||||
document.head.appendChild(s);
|
||||
|
||||
/*var s = this._main_style = document.createElement('style');
|
||||
|
||||
s.textContent = styles.style;
|
||||
s.id = "ffz-ui-css";
|
||||
|
||||
document.head.appendChild(s);
|
||||
document.head.appendChild(s);*/
|
||||
|
||||
if ( window.jQuery && jQuery.noty )
|
||||
jQuery.noty.themes.ffzTheme = {
|
||||
|
|
|
@ -42,6 +42,9 @@ var sanitize_el = document.createElement('span'),
|
|||
date_regex = /^(\d{4}|\+\d{6})(?:-?(\d{2})(?:-?(\d{2})(?:T(\d{2})(?::?(\d{2})(?::?(\d{2})(?:(?:\.|,)(\d{1,}))?)?)?(Z|([\-+])(\d{2})(?::?(\d{2}))?)?)?)?)?$/,
|
||||
|
||||
parse_date = function(str) {
|
||||
if ( typeof str === "number" )
|
||||
return new Date(str);
|
||||
|
||||
var parts = str.match(date_regex);
|
||||
if ( ! parts )
|
||||
return null;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue