mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-08-02 16:08:31 +00:00
3.5.66 to 3.5.77. Fixed a performance issue with chat scrolling. Fixed CSS issues introduced in the refactor. Added ReChat support. Fixed all tooltip positioning. Fixed emote usage reporting. Fix support for conversations beta. Fix Do Not Show Again link on portrait mode warning. Fix following data not loading on non-ember pages. Added emoji rendering when BTTV is detected. Made standard chat settings menu scroll. Added support for multiple commands with one button to in-line moderation icons.
This commit is contained in:
parent
0cabebdf19
commit
a050063c81
31 changed files with 885 additions and 275 deletions
23
dark.css
23
dark.css
|
@ -902,6 +902,26 @@
|
||||||
|
|
||||||
/* Conversations */
|
/* Conversations */
|
||||||
|
|
||||||
|
.ffz-dark .conversation-input-bar .emoticon-selector-toggle svg path {
|
||||||
|
fill: rgba(255,255,255,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ffz-dark .conversation-input-bar .emoticon-selector-toggle:hover svg path {
|
||||||
|
fill: rgba(255,255,255,0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ffz-dark .conversation-input-bar .emoticon-selector-box .emote-set {
|
||||||
|
border-color: #323232;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ffz-dark .conversation-input-bar .emoticon-selector-box .emoticon-grid {
|
||||||
|
background-color: #191919;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ffz-dark .ember-chat .chat-settings .experimental-options {
|
||||||
|
border-top-color: rgba(255,255,255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
.ffz-dark .conversation-settings-menu .options-divider {
|
.ffz-dark .conversation-settings-menu .options-divider {
|
||||||
border-bottom-color: rgba(255,255,255,0.2);
|
border-bottom-color: rgba(255,255,255,0.2);
|
||||||
}
|
}
|
||||||
|
@ -1012,5 +1032,8 @@
|
||||||
background-color: #6441a5
|
background-color: #6441a5
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ffz-dark .conversation-window .timestamp-line span,
|
||||||
.ffz-dark .conversation-window .new-message-divider span { background: transparent; }
|
.ffz-dark .conversation-window .new-message-divider span { background: transparent; }
|
||||||
|
|
||||||
|
.ffz-dark .conversation-window .timestamp-line:after,
|
||||||
.ffz-dark .conversation-window .new-message-divider:after { display: none; }
|
.ffz-dark .conversation-window .new-message-divider:after { display: none; }
|
|
@ -260,6 +260,10 @@ FFZ.prototype.render_badges = function(component, badges) {
|
||||||
var user = component.get('msgObject.from') || component.get('message.from.username'),
|
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');
|
room_id = component.get('msgObject.room') || App.__container__.lookup('controller:chat').get('currentRoom.id');
|
||||||
|
|
||||||
|
return this._render_badges(user, room_id, badges, component);
|
||||||
|
}
|
||||||
|
|
||||||
|
FFZ.prototype._render_badges = function(user, room_id, badges, component) {
|
||||||
var data = this.users[user];
|
var data = this.users[user];
|
||||||
if ( ! data || ! data.badges )
|
if ( ! data || ! data.badges )
|
||||||
return badges;
|
return badges;
|
||||||
|
|
|
@ -187,6 +187,43 @@ RGBColor.prototype.eq = function(rgb) {
|
||||||
return rgb.r === this.r && rgb.g === this.g && rgb.b === this.b;
|
return rgb.r === this.r && rgb.g === this.g && rgb.b === this.b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RGBColor.fromCSS = function(rgb) {
|
||||||
|
rgb = rgb.trim();
|
||||||
|
|
||||||
|
if ( rgb.charAt(0) === '#' )
|
||||||
|
return RGBColor.fromHex(rgb);
|
||||||
|
|
||||||
|
var match = /rgba?\( *(\d+%?) *, *(\d+%?) *, *(\d+%?) *(?:,[^\)]+)?\)/.exec(rgb);
|
||||||
|
if ( match ) {
|
||||||
|
var r = match[1],
|
||||||
|
g = match[2],
|
||||||
|
b = match[3];
|
||||||
|
|
||||||
|
if ( r.charAt(r.length-1) === '%' )
|
||||||
|
r = 255 * (parseInt(r) / 100);
|
||||||
|
else
|
||||||
|
r = parseInt(r);
|
||||||
|
|
||||||
|
if ( g.charAt(g.length-1) === '%' )
|
||||||
|
g = 255 * (parseInt(g) / 100);
|
||||||
|
else
|
||||||
|
g = parseInt(g);
|
||||||
|
|
||||||
|
if ( b.charAt(b.length-1) === '%' )
|
||||||
|
b = 255 * (parseInt(b) / 100);
|
||||||
|
else
|
||||||
|
b = parseInt(b);
|
||||||
|
|
||||||
|
return new RGBColor(
|
||||||
|
Math.min(Math.max(0, r), 255),
|
||||||
|
Math.min(Math.max(0, g), 255),
|
||||||
|
Math.min(Math.max(0, b), 255)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
RGBColor.fromHex = function(code) {
|
RGBColor.fromHex = function(code) {
|
||||||
var raw = parseInt(code.charAt(0) === '#' ? code.substr(1) : code, 16);
|
var raw = parseInt(code.charAt(0) === '#' ? code.substr(1) : code, 16);
|
||||||
return new RGBColor(
|
return new RGBColor(
|
||||||
|
@ -587,6 +624,9 @@ FFZ.prototype._update_colors = function(darkness_only) {
|
||||||
|
|
||||||
|
|
||||||
FFZ.prototype._handle_color = function(color) {
|
FFZ.prototype._handle_color = function(color) {
|
||||||
|
if ( color instanceof RGBColor )
|
||||||
|
color = color.toHex();
|
||||||
|
|
||||||
if ( ! color || this._colors.hasOwnProperty(color) )
|
if ( ! color || this._colors.hasOwnProperty(color) )
|
||||||
return this._colors[color];
|
return this._colors[color];
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@ module.exports = {
|
||||||
2: ["ws://localhost:8001/"]
|
2: ["ws://localhost:8001/"]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
TOOLTIP_DISTANCE: 50,
|
||||||
|
|
||||||
KNOWN_CODES: {
|
KNOWN_CODES: {
|
||||||
"#-?[\\\\/]": "#-/",
|
"#-?[\\\\/]": "#-/",
|
||||||
":-?(?:7|L)": ":-7",
|
":-?(?:7|L)": ":-7",
|
||||||
|
@ -42,6 +44,7 @@ module.exports = {
|
||||||
"Gr(a|e)yFace": "GrayFace"
|
"Gr(a|e)yFace": "GrayFace"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
TWITCH_BASE: 'http://static-cdn.jtvnw.net/emoticons/v1/',
|
||||||
EMOTE_MIRROR_BASE: SERVER + "twitch-emote-mirror/",
|
EMOTE_MIRROR_BASE: SERVER + "twitch-emote-mirror/",
|
||||||
|
|
||||||
EMOTE_REPLACEMENT_BASE: SERVER + "script/replacements/",
|
EMOTE_REPLACEMENT_BASE: SERVER + "script/replacements/",
|
||||||
|
|
|
@ -215,7 +215,13 @@ FFZ.prototype._modify_cindex = function(view) {
|
||||||
el.classList.add('ffz-channel');
|
el.classList.add('ffz-channel');
|
||||||
|
|
||||||
// Try changing the theater mode tooltip.
|
// Try changing the theater mode tooltip.
|
||||||
this.$('.theatre-button a').attr('title', 'Theater Mode (Alt+T)');
|
var tb = this.$('.theatre-button > a'),
|
||||||
|
opts = tb.data('tipsy');
|
||||||
|
|
||||||
|
tb.attr('title', 'Theater Mode (Alt+T)');
|
||||||
|
if ( opts && opts.options && typeof opts.options.gravity !== "function" )
|
||||||
|
opts.options.gravity = utils.tooltip_placement(constants.TOOLTIP_DISTANCE, opts.options.gravity || 'n');
|
||||||
|
|
||||||
|
|
||||||
this.ffzFixTitle();
|
this.ffzFixTitle();
|
||||||
this.ffzUpdateUptime();
|
this.ffzUpdateUptime();
|
||||||
|
@ -283,7 +289,7 @@ FFZ.prototype._modify_cindex = function(view) {
|
||||||
if ( ! btn ) {
|
if ( ! btn ) {
|
||||||
btn = document.createElement('span');
|
btn = document.createElement('span');
|
||||||
btn.id = 'ffz-ui-host-button';
|
btn.id = 'ffz-ui-host-button';
|
||||||
btn.className = 'button action tooltip';
|
btn.className = 'button action';
|
||||||
|
|
||||||
btn.addEventListener('click', this.ffzClickHost.bind(btn, this, false));
|
btn.addEventListener('click', this.ffzClickHost.bind(btn, this, false));
|
||||||
|
|
||||||
|
@ -295,6 +301,8 @@ FFZ.prototype._modify_cindex = function(view) {
|
||||||
container.insertBefore(btn, before);
|
container.insertBefore(btn, before);
|
||||||
else
|
else
|
||||||
container.appendChild(btn);
|
container.appendChild(btn);
|
||||||
|
|
||||||
|
jQuery(btn).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
|
||||||
}
|
}
|
||||||
|
|
||||||
btn.classList.remove('disabled');
|
btn.classList.remove('disabled');
|
||||||
|
@ -321,7 +329,7 @@ FFZ.prototype._modify_cindex = function(view) {
|
||||||
if ( ! btn ) {
|
if ( ! btn ) {
|
||||||
btn = document.createElement('span');
|
btn = document.createElement('span');
|
||||||
btn.id = 'ffz-ui-host-button';
|
btn.id = 'ffz-ui-host-button';
|
||||||
btn.className = 'button action tooltip';
|
btn.className = 'button action';
|
||||||
|
|
||||||
btn.addEventListener('click', this.ffzClickHost.bind(btn, this, true));
|
btn.addEventListener('click', this.ffzClickHost.bind(btn, this, true));
|
||||||
|
|
||||||
|
@ -333,6 +341,8 @@ FFZ.prototype._modify_cindex = function(view) {
|
||||||
container.insertBefore(btn, before);
|
container.insertBefore(btn, before);
|
||||||
else
|
else
|
||||||
container.appendChild(btn);
|
container.appendChild(btn);
|
||||||
|
|
||||||
|
jQuery(btn).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
|
||||||
}
|
}
|
||||||
|
|
||||||
btn.classList.remove('disabled');
|
btn.classList.remove('disabled');
|
||||||
|
@ -406,7 +416,7 @@ FFZ.prototype._modify_cindex = function(view) {
|
||||||
else
|
else
|
||||||
cont.appendChild(stat);
|
cont.appendChild(stat);
|
||||||
|
|
||||||
jQuery(stat).tipsy();
|
jQuery(stat).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
|
||||||
}
|
}
|
||||||
|
|
||||||
el.innerHTML = utils.number_commas(chatter_count);
|
el.innerHTML = utils.number_commas(chatter_count);
|
||||||
|
@ -438,7 +448,7 @@ FFZ.prototype._modify_cindex = function(view) {
|
||||||
else
|
else
|
||||||
cont.appendChild(stat);
|
cont.appendChild(stat);
|
||||||
|
|
||||||
jQuery(stat).tipsy();
|
jQuery(stat).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
|
||||||
}
|
}
|
||||||
|
|
||||||
el.innerHTML = utils.number_commas(ffz_viewers) + " (" + utils.number_commas(ffz_chatters) + ")";
|
el.innerHTML = utils.number_commas(ffz_viewers) + " (" + utils.number_commas(ffz_chatters) + ")";
|
||||||
|
@ -473,7 +483,7 @@ FFZ.prototype._modify_cindex = function(view) {
|
||||||
if ( ! stat_el ) {
|
if ( ! stat_el ) {
|
||||||
stat_el = document.createElement('span');
|
stat_el = document.createElement('span');
|
||||||
stat_el.id = 'ffz-ui-player-stats';
|
stat_el.id = 'ffz-ui-player-stats';
|
||||||
stat_el.className = 'ffz stat tooltip';
|
stat_el.className = 'ffz stat';
|
||||||
|
|
||||||
stat_el.innerHTML = constants.GRAPH + " ";
|
stat_el.innerHTML = constants.GRAPH + " ";
|
||||||
el = document.createElement('span');
|
el = document.createElement('span');
|
||||||
|
@ -484,16 +494,18 @@ FFZ.prototype._modify_cindex = function(view) {
|
||||||
container.insertBefore(stat_el, other.nextSibling);
|
container.insertBefore(stat_el, other.nextSibling);
|
||||||
else
|
else
|
||||||
container.appendChild(stat_el);
|
container.appendChild(stat_el);
|
||||||
|
|
||||||
|
jQuery(stat_el).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
|
||||||
}
|
}
|
||||||
|
|
||||||
var delay = parseFloat(stats.hlsLatencyBroadcaster);
|
var delay = parseFloat(stats.hlsLatencyBroadcaster);
|
||||||
|
|
||||||
if ( delay > 180 ) {
|
if ( delay > 180 ) {
|
||||||
delay = Math.floor(delay);
|
delay = Math.floor(delay);
|
||||||
stat_el.setAttribute('original-title', 'Video Information\nBroadcast ' + utils.time_to_string(delay, true) + ' Ago\n\nVideo: ' + stats.videoResolution + 'p @ ' + stats.fps + '\nPlayback Rate: ' + stats.playbackRate + ' Kbps')
|
stat_el.setAttribute('original-title', 'Video Information<br>Broadcast ' + utils.time_to_string(delay, true) + ' Ago<br><br>Video: ' + stats.videoResolution + 'p @ ' + stats.fps + '<br>Playback Rate: ' + stats.playbackRate + ' Kbps')
|
||||||
el.textContent = utils.time_to_string(Math.floor(delay), true, delay > 172800) + ' old';
|
el.textContent = utils.time_to_string(Math.floor(delay), true, delay > 172800) + ' old';
|
||||||
} else {
|
} else {
|
||||||
stat_el.setAttribute('original-title', 'Stream Latency\nVideo: ' + stats.videoResolution + 'p @ ' + stats.fps + '\nPlayback Rate: ' + stats.playbackRate + ' Kbps');
|
stat_el.setAttribute('original-title', 'Stream Latency<br>Video: ' + stats.videoResolution + 'p @ ' + stats.fps + '<br>Playback Rate: ' + stats.playbackRate + ' Kbps');
|
||||||
|
|
||||||
delay = stats.hlsLatencyBroadcaster;
|
delay = stats.hlsLatencyBroadcaster;
|
||||||
var pos = delay.lastIndexOf('.');
|
var pos = delay.lastIndexOf('.');
|
||||||
|
@ -532,7 +544,7 @@ FFZ.prototype._modify_cindex = function(view) {
|
||||||
if ( ! stat_el ) {
|
if ( ! stat_el ) {
|
||||||
stat_el = document.createElement('span');
|
stat_el = document.createElement('span');
|
||||||
stat_el.id = 'ffz-ui-player-stats';
|
stat_el.id = 'ffz-ui-player-stats';
|
||||||
stat_el.className = 'ffz stat tooltip';
|
stat_el.className = 'ffz stat';
|
||||||
|
|
||||||
stat_el.innerHTML = constants.GRAPH + " ";
|
stat_el.innerHTML = constants.GRAPH + " ";
|
||||||
el = document.createElement('span');
|
el = document.createElement('span');
|
||||||
|
@ -543,16 +555,18 @@ FFZ.prototype._modify_cindex = function(view) {
|
||||||
container.insertBefore(stat_el, other.nextSibling);
|
container.insertBefore(stat_el, other.nextSibling);
|
||||||
else
|
else
|
||||||
container.appendChild(stat_el);
|
container.appendChild(stat_el);
|
||||||
|
|
||||||
|
jQuery(stat_el).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
|
||||||
}
|
}
|
||||||
|
|
||||||
var delay = parseFloat(stats.hlsLatencyBroadcaster);
|
var delay = parseFloat(stats.hlsLatencyBroadcaster);
|
||||||
|
|
||||||
if ( delay > 180 ) {
|
if ( delay > 180 ) {
|
||||||
delay = Math.floor(delay);
|
delay = Math.floor(delay);
|
||||||
stat_el.setAttribute('original-title', 'Video Information\nBroadcast ' + utils.time_to_string(delay, true) + ' Ago\n\nVideo: ' + stats.videoResolution + 'p @ ' + stats.fps + '\nPlayback Rate: ' + stats.playbackRate + ' Kbps')
|
stat_el.setAttribute('original-title', 'Video Information<br>Broadcast ' + utils.time_to_string(delay, true) + ' Ago<br><br>Video: ' + stats.videoResolution + 'p @ ' + stats.fps + '<br>Playback Rate: ' + stats.playbackRate + ' Kbps')
|
||||||
el.textContent = utils.time_to_string(Math.floor(delay), true, delay > 172800) + ' old';
|
el.textContent = utils.time_to_string(Math.floor(delay), true, delay > 172800) + ' old';
|
||||||
} else {
|
} else {
|
||||||
stat_el.setAttribute('original-title', 'Stream Latency\nVideo: ' + stats.videoResolution + 'p @ ' + stats.fps + '\nPlayback Rate: ' + stats.playbackRate + ' Kbps');
|
stat_el.setAttribute('original-title', 'Stream Latency<br>Video: ' + stats.videoResolution + 'p @ ' + stats.fps + '<br>Playback Rate: ' + stats.playbackRate + ' Kbps');
|
||||||
|
|
||||||
delay = stats.hlsLatencyBroadcaster;
|
delay = stats.hlsLatencyBroadcaster;
|
||||||
var pos = delay.lastIndexOf('.');
|
var pos = delay.lastIndexOf('.');
|
||||||
|
@ -624,7 +638,7 @@ FFZ.prototype._modify_cindex = function(view) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jQuery(stat).tipsy({html: true});
|
jQuery(stat).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
|
||||||
}
|
}
|
||||||
|
|
||||||
el.innerHTML = utils.time_to_string(uptime, false, false, false, f.settings.stream_uptime === 1 || f.settings.stream_uptime === 3);
|
el.innerHTML = utils.time_to_string(uptime, false, false, false, f.settings.stream_uptime === 1 || f.settings.stream_uptime === 3);
|
||||||
|
|
|
@ -415,7 +415,7 @@ FFZ.prototype._modify_cview = function(view) {
|
||||||
ffzInit: function() {
|
ffzInit: function() {
|
||||||
f._chatv = this;
|
f._chatv = this;
|
||||||
this.$('.textarea-contain').append(f.build_ui_link(this));
|
this.$('.textarea-contain').append(f.build_ui_link(this));
|
||||||
this.$('.chat-messages').find('.html-tooltip').tipsy({live: true, html: true, gravity: jQuery.fn.tipsy.autoNS});
|
this.$('.chat-messages').find('.html-tooltip').tipsy({live: true, html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
|
||||||
|
|
||||||
if ( !f.has_bttv && f.settings.group_tabs )
|
if ( !f.has_bttv && f.settings.group_tabs )
|
||||||
this.ffzEnableTabs();
|
this.ffzEnableTabs();
|
||||||
|
@ -447,7 +447,7 @@ FFZ.prototype._modify_cview = function(view) {
|
||||||
var room = this.get('controller.currentRoom'), rows;
|
var room = this.get('controller.currentRoom'), rows;
|
||||||
room && room.resetUnreadCount();
|
room && room.resetUnreadCount();
|
||||||
|
|
||||||
if ( room._ffz_was_unread ) {
|
if ( room && room._ffz_was_unread ) {
|
||||||
room._ffz_was_unread = false;
|
room._ffz_was_unread = false;
|
||||||
|
|
||||||
var el = this.get('element'),
|
var el = this.get('element'),
|
||||||
|
|
|
@ -7,23 +7,11 @@ var FFZ = window.FrankerFaceZ,
|
||||||
// Settings
|
// Settings
|
||||||
// ---------------
|
// ---------------
|
||||||
|
|
||||||
FFZ.settings_info.conv_title_clickable = {
|
|
||||||
type: "boolean",
|
|
||||||
value: false,
|
|
||||||
no_mobile: true,
|
|
||||||
|
|
||||||
category: "Conversations",
|
|
||||||
name: "Clickable Header Name",
|
|
||||||
help: "Make the conversation header a link that takes you to that person's page.",
|
|
||||||
on_update: function(val) {
|
|
||||||
document.body.classList.toggle('ffz-conv-title-clickable', val);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
FFZ.settings_info.conv_focus_on_click = {
|
FFZ.settings_info.conv_focus_on_click = {
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
value: false,
|
value: false,
|
||||||
no_mobile: true,
|
no_mobile: true,
|
||||||
|
visible: false,
|
||||||
|
|
||||||
category: "Conversations",
|
category: "Conversations",
|
||||||
name: "Focus Input on Click",
|
name: "Focus Input on Click",
|
||||||
|
@ -43,19 +31,6 @@ FFZ.settings_info.top_conversations = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
FFZ.settings_info.conv_beta_enable = {
|
|
||||||
type: "boolean",
|
|
||||||
value: false,
|
|
||||||
no_mobile: true,
|
|
||||||
|
|
||||||
category: "Conversations",
|
|
||||||
name: "Enable Conversations",
|
|
||||||
help: "Twitch hasn't enabled them yet, but they're in the code for testing. Try them out!",
|
|
||||||
on_update: function(val) {
|
|
||||||
App.__container__.lookup('route:application').controller.set('isConversationsEnabled', val);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// ---------------
|
// ---------------
|
||||||
// Initialization
|
// Initialization
|
||||||
|
@ -63,10 +38,6 @@ FFZ.settings_info.conv_beta_enable = {
|
||||||
|
|
||||||
FFZ.prototype.setup_conversations = function() {
|
FFZ.prototype.setup_conversations = function() {
|
||||||
document.body.classList.toggle('ffz-top-conversations', this.settings.top_conversations);
|
document.body.classList.toggle('ffz-top-conversations', this.settings.top_conversations);
|
||||||
document.body.classList.toggle('ffz-conv-title-clickable', this.settings.conv_title_clickable);;
|
|
||||||
|
|
||||||
if ( this.settings.conv_beta_enable )
|
|
||||||
App.__container__.lookup('route:application').controller.set('isConversationsEnabled', true);
|
|
||||||
|
|
||||||
this.log("Hooking the Ember Conversation Window component.");
|
this.log("Hooking the Ember Conversation Window component.");
|
||||||
var ConvWindow = App.__container__.resolve('component:conversation-window');
|
var ConvWindow = App.__container__.resolve('component:conversation-window');
|
||||||
|
@ -78,6 +49,9 @@ FFZ.prototype.setup_conversations = function() {
|
||||||
var ConvLine = App.__container__.resolve('component:conversation-line');
|
var ConvLine = App.__container__.resolve('component:conversation-line');
|
||||||
if ( ConvLine )
|
if ( ConvLine )
|
||||||
this._modify_conversation_line(ConvLine);
|
this._modify_conversation_line(ConvLine);
|
||||||
|
|
||||||
|
// TODO: Make this better later.
|
||||||
|
jQuery('.conversations-list').find('.html-tooltip').tipsy({live: true, html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -88,14 +62,8 @@ FFZ.prototype._modify_conversation_window = function(component) {
|
||||||
Settings = App.__container__.lookup('controller:settings');
|
Settings = App.__container__.lookup('controller:settings');
|
||||||
|
|
||||||
component.reopen({
|
component.reopen({
|
||||||
onConversationClick: Ember.on('click', function() {
|
headerBadges: Ember.computed("thread.participants", "currentUsername", function() {
|
||||||
this.markConversationRead();
|
var e = this.get("thread.participants").rejectBy("username", this.get("currentUsername")).objectAt(0),
|
||||||
if ( f.settings.conv_focus_on_click )
|
|
||||||
this.$(".conversation-input-bar textarea").focus();
|
|
||||||
}),
|
|
||||||
|
|
||||||
headerBadges: Ember.computed("conversation.participants", "currentUsername", function() {
|
|
||||||
var e = this.get("conversation.participants").rejectBy("username", this.get("currentUsername")).objectAt(0),
|
|
||||||
badges = {},
|
badges = {},
|
||||||
|
|
||||||
ut = e.get("userType");
|
ut = e.get("userType");
|
||||||
|
@ -164,28 +132,18 @@ FFZ.prototype._modify_conversation_window = function(component) {
|
||||||
header = el && el.querySelector('.conversation-header'),
|
header = el && el.querySelector('.conversation-header'),
|
||||||
header_name = header && header.querySelector('.conversation-header-name'),
|
header_name = header && header.querySelector('.conversation-header-name'),
|
||||||
|
|
||||||
new_header_name = document.createElement('span'),
|
|
||||||
|
|
||||||
raw_color = this.get('otherUser.color'),
|
raw_color = this.get('otherUser.color'),
|
||||||
colors = raw_color && f._handle_color(raw_color),
|
colors = raw_color && f._handle_color(raw_color),
|
||||||
|
|
||||||
is_dark = (Layout && Layout.get('isTheatreMode')) || f.settings.dark_twitch;
|
is_dark = (Layout && Layout.get('isTheatreMode')) || f.settings.dark_twitch;
|
||||||
|
|
||||||
if ( header_name ) {
|
if ( header_name && raw_color ) {
|
||||||
new_header_name.className = 'conversation-header-name';
|
header_name.style.color = (is_dark ? colors[1] : colors[0]);
|
||||||
new_header_name.textContent = header_name.textContent;
|
header_name.classList.add('has-color');
|
||||||
header.insertBefore(new_header_name, header_name);
|
header_name.setAttribute('data-color', raw_color);
|
||||||
|
|
||||||
if ( raw_color ) {
|
|
||||||
header_name.style.color = (is_dark ? colors[1] : colors[0]);
|
|
||||||
header_name.classList.add('has-color');
|
|
||||||
header_name.setAttribute('data-color', raw_color);
|
|
||||||
|
|
||||||
new_header_name.style.color = (is_dark ? colors[1] : colors[0]);
|
|
||||||
new_header_name.classList.add('has-color');
|
|
||||||
new_header_name.setAttribute('data-color', raw_color);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jQuery(el).find('.html-tooltip').tipsy({live: true, html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ FFZ.prototype._modify_directory_live = function(dir, is_csgo) {
|
||||||
var t_el = this._ffz_uptime = document.createElement('div');
|
var t_el = this._ffz_uptime = document.createElement('div');
|
||||||
t_el.className = 'overlay_info length live';
|
t_el.className = 'overlay_info length live';
|
||||||
|
|
||||||
jQuery(t_el).tipsy({html: true});
|
jQuery(t_el).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 's')});
|
||||||
|
|
||||||
cap.appendChild(t_el);
|
cap.appendChild(t_el);
|
||||||
this._ffz_uptime_timer = setInterval(this.ffzUpdateUptime.bind(this), 1000);
|
this._ffz_uptime_timer = setInterval(this.ffzUpdateUptime.bind(this), 1000);
|
||||||
|
|
|
@ -159,7 +159,7 @@ FFZ.prototype.setup_profile_following = function() {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
t_el.className = 'overlay_info length';
|
t_el.className = 'overlay_info length';
|
||||||
jQuery(t_el).tipsy({html: true});
|
jQuery(t_el).tipsy({html: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 's')});
|
||||||
|
|
||||||
var age = data[0] ? Math.floor((Date.now() - data[0].getTime()) / 1000) : 0;
|
var age = data[0] ? Math.floor((Date.now() - data[0].getTime()) / 1000) : 0;
|
||||||
if ( age ) {
|
if ( age ) {
|
||||||
|
|
|
@ -228,7 +228,7 @@ FFZ.prototype.setup_layout = function() {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
f._portrait_warning = true;
|
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>');
|
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="ffz.settings.set(\'portrait_warning\',true);jQuery(this).parents(\'.ffz-noty\').remove();return false">Do not show this message again</a>');
|
||||||
|
|
||||||
}.observes("isTooSmallForRightColumn"),
|
}.observes("isTooSmallForRightColumn"),
|
||||||
|
|
||||||
|
|
|
@ -113,7 +113,7 @@ FFZ.settings_info.scrollback_length = {
|
||||||
|
|
||||||
for(var room_id in this.rooms) {
|
for(var room_id in this.rooms) {
|
||||||
var room = this.rooms[room_id];
|
var room = this.rooms[room_id];
|
||||||
room.room.set('messageBufferSize', new_val + ((this._roomv && !this._roomv.get('stuckToBottom') && current_id === room_id) ? 150 : 0));
|
room.room && room.room.set('messageBufferSize', new_val + ((this._roomv && !this._roomv.get('stuckToBottom') && current_id === room_id) ? 150 : 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -149,7 +149,6 @@ FFZ.settings_info.banned_words = {
|
||||||
|
|
||||||
category: "Chat Filtering",
|
category: "Chat Filtering",
|
||||||
no_bttv: true,
|
no_bttv: true,
|
||||||
//visible: function() { return ! this.has_bttv },
|
|
||||||
|
|
||||||
name: "Banned Words",
|
name: "Banned Words",
|
||||||
help: "Set a list of words that will be locally removed from chat messages.",
|
help: "Set a list of words that will be locally removed from chat messages.",
|
||||||
|
@ -181,7 +180,6 @@ FFZ.settings_info.keywords = {
|
||||||
|
|
||||||
category: "Chat Filtering",
|
category: "Chat Filtering",
|
||||||
no_bttv: true,
|
no_bttv: true,
|
||||||
//visible: function() { return ! this.has_bttv },
|
|
||||||
|
|
||||||
name: "Highlight Keywords",
|
name: "Highlight Keywords",
|
||||||
help: "Set additional keywords that will be highlighted in chat.",
|
help: "Set additional keywords that will be highlighted in chat.",
|
||||||
|
@ -246,6 +244,21 @@ FFZ.settings_info.link_image_hover = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
FFZ.settings_info.emote_image_hover = {
|
||||||
|
type: "boolean",
|
||||||
|
value: false,
|
||||||
|
|
||||||
|
category: "Chat Tooltips",
|
||||||
|
no_mobile: true,
|
||||||
|
|
||||||
|
name: "Emote Preview",
|
||||||
|
help: "Display scaled up high-DPI emoticon images in tooltips to help see details on low-resolution monitors.",
|
||||||
|
on_update: function(val) {
|
||||||
|
this._reset_tooltips();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
FFZ.settings_info.image_hover_all_domains = {
|
FFZ.settings_info.image_hover_all_domains = {
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
value: false,
|
value: false,
|
||||||
|
@ -402,7 +415,7 @@ FFZ.settings_info.chat_font_family = {
|
||||||
|
|
||||||
var span = document.createElement('span');
|
var span = document.createElement('span');
|
||||||
span.style.fontFamily = val;
|
span.style.fontFamily = val;
|
||||||
css = ".ember-chat .chat-messages {" + span.style.cssText + "}";
|
css = ".timestamp-line,.conversation-chat-line,.conversation-system-messages,.chat-history,.ember-chat .chat-messages {" + span.style.cssText + "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.update_css(this._chat_style, "chat_font_family", css);
|
utils.update_css(this._chat_style, "chat_font_family", css);
|
||||||
|
@ -444,7 +457,7 @@ FFZ.settings_info.chat_font_size = {
|
||||||
else {
|
else {
|
||||||
var lh = Math.max(20, Math.round((20/12)*val)),
|
var lh = Math.max(20, Math.round((20/12)*val)),
|
||||||
pd = Math.floor((lh - 20) / 2);
|
pd = Math.floor((lh - 20) / 2);
|
||||||
css = ".ember-chat .chat-messages .chat-line { font-size: " + val + "px !important; line-height: " + lh + "px !important; }";
|
css = ".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 )
|
if ( pd )
|
||||||
css += ".ember-chat .chat-messages .chat-line .mod-icons, .ember-chat .chat-messages .chat-line .badges { padding-top: " + pd + "px; }";
|
css += ".ember-chat .chat-messages .chat-line .mod-icons, .ember-chat .chat-messages .chat-line .badges { padding-top: " + pd + "px; }";
|
||||||
}
|
}
|
||||||
|
@ -492,7 +505,7 @@ FFZ.settings_info.chat_ts_size = {
|
||||||
css = "";
|
css = "";
|
||||||
else {
|
else {
|
||||||
var lh = Math.max(20, Math.round((20/12)*val), Math.round((20/12)*this.settings.chat_font_size));
|
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 = ".chat-history .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);
|
utils.update_css(this._chat_style, "chat_ts_font_size", css);
|
||||||
|
@ -607,11 +620,13 @@ FFZ.prototype._modify_line = function(component) {
|
||||||
if ( e.target.classList.contains('custom') ) {
|
if ( e.target.classList.contains('custom') ) {
|
||||||
var room_id = this.get('msgObject.room'),
|
var room_id = this.get('msgObject.room'),
|
||||||
room = room_id && f.rooms[room_id] && f.rooms[room_id].room,
|
room = room_id && f.rooms[room_id] && f.rooms[room_id].room,
|
||||||
|
|
||||||
cmd = e.target.getAttribute('data-cmd');
|
cmd = e.target.getAttribute('data-cmd');
|
||||||
|
|
||||||
if ( room ) {
|
if ( room ) {
|
||||||
room.send(cmd, true);
|
var lines = cmd.split("\n");
|
||||||
|
for(var i=0; i < lines.length; i++)
|
||||||
|
room.send(lines[i], true);
|
||||||
|
|
||||||
if ( e.target.classList.contains('is-timeout') )
|
if ( e.target.classList.contains('is-timeout') )
|
||||||
room.clearMessages(this.get('msgObject.from'));
|
room.clearMessages(this.get('msgObject.from'));
|
||||||
}
|
}
|
||||||
|
@ -683,8 +698,8 @@ FFZ.prototype._modify_line = function(component) {
|
||||||
|
|
||||||
else {
|
else {
|
||||||
if ( typeof btn === "string" ) {
|
if ( typeof btn === "string" ) {
|
||||||
cmd = btn.replace(/{user}/g, user);
|
cmd = btn.replace(/{user}/g, user).replace(/ *<LINE> */, "\n");
|
||||||
tip = 'Custom Command\n' + cmd;
|
tip = 'Custom Command' + (cmd.indexOf('\n') !== -1 ? 's' : '') + '\n' + cmd;
|
||||||
} else {
|
} else {
|
||||||
cmd = "/timeout " + user + " " + btn;
|
cmd = "/timeout " + user + " " + btn;
|
||||||
tip = "Timeout User (" + utils.duration_string(btn) + ")";
|
tip = "Timeout User (" + utils.duration_string(btn) + ")";
|
||||||
|
|
|
@ -182,7 +182,7 @@ FFZ.settings_info.mod_buttons = {
|
||||||
old_val += ' ' + prefix + cmd;
|
old_val += ' ' + prefix + cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
var new_val = prompt("Custom In-Line Moderation Icons\n\nPlease enter a list of commands to be made available as mod icons within chat lines. Commands are separated by spaces. To include spaces in a command, surround the command with double quotes (\"). Use \"{user}\" to insert the user's username into the command, otherwise it will be appended to the end.\n\nExample: !permit \"!reg add {user}\"\n\nNumeric values will become timeout buttons for that number of seconds. The text \"<BAN>\" is a special value that will act like the normal Ban button in chat.\n\nTo assign a specific letter for use as the icon, specify it at the start of the command followed by an equals sign.\n\nExample: A=\"!reg add\"\n\nDefault: <BAN> 600", old_val);
|
var new_val = prompt("Custom In-Line Moderation Icons\n\nPlease enter a list of commands to be made available as mod icons within chat lines. Commands are separated by spaces. To include spaces in a command, surround the command with double quotes (\"). Use \"{user}\" to insert the user's username into the command, otherwise it will be appended to the end.\n\nExample: !permit \"!reg add {user}\"\n\nTo send multiple commands, separate them with \"<LINE>\".\n\nNumeric values will become timeout buttons for that number of seconds. The text \"<BAN>\" is a special value that will act like the normal Ban button in chat.\n\nTo assign a specific letter for use as the icon, specify it at the start of the command followed by an equals sign.\n\nExample: A=\"!reg add\"\n\nDefault: <BAN> 600", old_val);
|
||||||
|
|
||||||
if ( new_val === null || new_val === undefined )
|
if ( new_val === null || new_val === undefined )
|
||||||
return;
|
return;
|
||||||
|
@ -253,8 +253,15 @@ FFZ.settings_info.mod_buttons = {
|
||||||
} else
|
} else
|
||||||
had_prefix = true;
|
had_prefix = true;
|
||||||
|
|
||||||
if ( typeof val === "string" && val.indexOf('{user}') === -1 )
|
if ( typeof val === "string" ) {
|
||||||
val += ' {user}';
|
// Split it up for this step.
|
||||||
|
var lines = val.split(/ *<LINE> */);
|
||||||
|
for(var x=0; x < lines.length; x++) {
|
||||||
|
if ( lines[x].indexOf('{user}') === -1 )
|
||||||
|
lines[x] += ' {user}';
|
||||||
|
}
|
||||||
|
val = lines.join("<LINE>");
|
||||||
|
}
|
||||||
|
|
||||||
final.push([prefix, val, had_prefix]);
|
final.push([prefix, val, had_prefix]);
|
||||||
}
|
}
|
||||||
|
@ -475,7 +482,7 @@ FFZ.prototype.setup_mod_card = function() {
|
||||||
if ( name ) {
|
if ( name ) {
|
||||||
name.classList.add('ffz-alias');
|
name.classList.add('ffz-alias');
|
||||||
name.title = utils.sanitize(controller.get('cardInfo.user.display_name') || user_id.capitalize());
|
name.title = utils.sanitize(controller.get('cardInfo.user.display_name') || user_id.capitalize());
|
||||||
jQuery(name).tipsy();
|
jQuery(name).tipsy({gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,7 +529,7 @@ FFZ.prototype.setup_mod_card = function() {
|
||||||
btn.innerHTML = utils.sanitize(title);
|
btn.innerHTML = utils.sanitize(title);
|
||||||
btn.title = utils.sanitize(cmd.replace(/{user}/g, controller.get('cardInfo.user.id') || '{user}'));
|
btn.title = utils.sanitize(cmd.replace(/{user}/g, controller.get('cardInfo.user.id') || '{user}'));
|
||||||
|
|
||||||
jQuery(btn).tipsy();
|
jQuery(btn).tipsy({gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
|
||||||
btn.addEventListener('click', add_btn_click.bind(this, cmd));
|
btn.addEventListener('click', add_btn_click.bind(this, cmd));
|
||||||
return btn;
|
return btn;
|
||||||
};
|
};
|
||||||
|
@ -601,7 +608,7 @@ FFZ.prototype.setup_mod_card = function() {
|
||||||
else if ( f.settings.mod_card_hotkeys && timeout === 1 )
|
else if ( f.settings.mod_card_hotkeys && timeout === 1 )
|
||||||
btn.title = "(P)urge - " + btn.title;
|
btn.title = "(P)urge - " + btn.title;
|
||||||
|
|
||||||
jQuery(btn).tipsy();
|
jQuery(btn).tipsy({gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
|
||||||
|
|
||||||
btn.addEventListener('click', btn_click.bind(this, timeout));
|
btn.addEventListener('click', btn_click.bind(this, timeout));
|
||||||
return btn;
|
return btn;
|
||||||
|
@ -637,7 +644,7 @@ FFZ.prototype.setup_mod_card = function() {
|
||||||
unban_btn.innerHTML = CHECK;
|
unban_btn.innerHTML = CHECK;
|
||||||
unban_btn.title = (f.settings.mod_card_hotkeys ? "(U)" : "U") + "nban User";
|
unban_btn.title = (f.settings.mod_card_hotkeys ? "(U)" : "U") + "nban User";
|
||||||
|
|
||||||
jQuery(unban_btn).tipsy();
|
jQuery(unban_btn).tipsy({gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
|
||||||
unban_btn.addEventListener("click", btn_click.bind(this, -1));
|
unban_btn.addEventListener("click", btn_click.bind(this, -1));
|
||||||
|
|
||||||
jQuery(ban_btn).after(unban_btn);
|
jQuery(ban_btn).after(unban_btn);
|
||||||
|
@ -661,7 +668,7 @@ FFZ.prototype.setup_mod_card = function() {
|
||||||
msg_btn.classList.add('message');
|
msg_btn.classList.add('message');
|
||||||
|
|
||||||
msg_btn.title = "Whisper User";
|
msg_btn.title = "Whisper User";
|
||||||
jQuery(msg_btn).tipsy();
|
jQuery(msg_btn).tipsy({gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
|
||||||
|
|
||||||
|
|
||||||
var real_msg = document.createElement('button');
|
var real_msg = document.createElement('button');
|
||||||
|
@ -846,7 +853,7 @@ FFZ.prototype._build_mod_card_history = function(line) {
|
||||||
// Interactivity
|
// Interactivity
|
||||||
jQuery('a.deleted-link', l_el).click(f._deleted_link_click);
|
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('img.emoticon', l_el).click(function(e) { f._click_emote(this, e) });
|
||||||
jQuery('.html-tooltip', l_el).tipsy({html:true});
|
jQuery('.html-tooltip', l_el).tipsy({html:true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 's')});
|
||||||
|
|
||||||
return l_el;
|
return l_el;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ FFZ.prototype.setup_player = function() {
|
||||||
|
|
||||||
this.players = {};
|
this.players = {};
|
||||||
|
|
||||||
var Player2 = App && App.__container__.resolve('component:twitch-player2');
|
var Player2 = window.App && App.__container__.resolve('component:twitch-player2');
|
||||||
if ( ! Player2 )
|
if ( ! Player2 )
|
||||||
return this.log("Unable to find twitch-player2 component.");
|
return this.log("Unable to find twitch-player2 component.");
|
||||||
|
|
||||||
|
|
|
@ -134,6 +134,15 @@ FFZ.prototype._modify_rview = function(view) {
|
||||||
this._super();
|
this._super();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
ffzAlternate: function() {
|
||||||
|
/*if ( ! this._ffz_chat_display ) {
|
||||||
|
var el = this.get('element');
|
||||||
|
this._ffz_chat_display = el && el.querySelector('ul.chat-lines');
|
||||||
|
}
|
||||||
|
|
||||||
|
this._ffz_chat_display && this._ffz_chat_display.classList.toggle('ffz-should-alternate');*/
|
||||||
|
},
|
||||||
|
|
||||||
ffzInit: function() {
|
ffzInit: function() {
|
||||||
f._roomv = this;
|
f._roomv = this;
|
||||||
|
|
||||||
|
@ -179,6 +188,9 @@ FFZ.prototype._modify_rview = function(view) {
|
||||||
if ( f._roomv === this )
|
if ( f._roomv === this )
|
||||||
f._roomv = undefined;
|
f._roomv = undefined;
|
||||||
|
|
||||||
|
if ( this._ffz_chat_display )
|
||||||
|
this._ffz_chat_display = undefined;
|
||||||
|
|
||||||
this.ffzDisableFreeze();
|
this.ffzDisableFreeze();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -367,12 +379,12 @@ FFZ.prototype._modify_rview = function(view) {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
ffzUnfreeze: function() {
|
ffzUnfreeze: function(from_stuck) {
|
||||||
this.ffz_frozen = false;
|
this.ffz_frozen = false;
|
||||||
this._ffz_last_move = 0;
|
this._ffz_last_move = 0;
|
||||||
this.ffzUnwarnPaused();
|
this.ffzUnwarnPaused();
|
||||||
|
|
||||||
if ( this.get('stuckToBottom') )
|
if ( ! from_stuck && this.get('stuckToBottom') )
|
||||||
this._scrollToBottom();
|
this._scrollToBottom();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -434,7 +446,7 @@ FFZ.prototype._modify_rview = function(view) {
|
||||||
this.set("stuckToBottom", val);
|
this.set("stuckToBottom", val);
|
||||||
this.get("controller.model") && this.set("controller.model.messageBufferSize", f.settings.scrollback_length + (val ? 0 : 150));
|
this.get("controller.model") && this.set("controller.model.messageBufferSize", f.settings.scrollback_length + (val ? 0 : 150));
|
||||||
if ( ! val )
|
if ( ! val )
|
||||||
this.ffzUnfreeze();
|
this.ffzUnfreeze(true);
|
||||||
},
|
},
|
||||||
|
|
||||||
// Warnings~!
|
// Warnings~!
|
||||||
|
@ -728,6 +740,7 @@ FFZ.prototype._insert_history = function(room_id, data) {
|
||||||
tmiSession = r.tmiSession || (TMI._sessions && TMI._sessions[0]),
|
tmiSession = r.tmiSession || (TMI._sessions && TMI._sessions[0]),
|
||||||
tmiRoom = r.tmiRoom,
|
tmiRoom = r.tmiRoom,
|
||||||
|
|
||||||
|
removed = 0,
|
||||||
inserted = 0,
|
inserted = 0,
|
||||||
purged = {},
|
purged = {},
|
||||||
|
|
||||||
|
@ -828,10 +841,15 @@ FFZ.prototype._insert_history = function(room_id, data) {
|
||||||
this.tokenize_chat_line(msg, true, r.get('roomProperties.hide_chat_links'));
|
this.tokenize_chat_line(msg, true, r.get('roomProperties.hide_chat_links'));
|
||||||
if ( r.shouldShowMessage(msg) ) {
|
if ( r.shouldShowMessage(msg) ) {
|
||||||
messages.insertAt(inserted, msg);
|
messages.insertAt(inserted, msg);
|
||||||
while( messages.length > r.get('messageBufferSize') )
|
while( messages.length > r.get('messageBufferSize') ) {
|
||||||
messages.removeAt(0);
|
messages.removeAt(0);
|
||||||
|
removed++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( (removed % 2) && this._roomv && this._roomv.get('context.model.id') === room_id )
|
||||||
|
this._roomv.ffzAlternate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -995,7 +1013,8 @@ FFZ.prototype._modify_room = function(room) {
|
||||||
|
|
||||||
var msgs = t.get('messages'),
|
var msgs = t.get('messages'),
|
||||||
total = msgs.get('length'),
|
total = msgs.get('length'),
|
||||||
i = total;
|
i = total,
|
||||||
|
removed = 0;
|
||||||
|
|
||||||
// Delete visible messages
|
// Delete visible messages
|
||||||
while(i--) {
|
while(i--) {
|
||||||
|
@ -1004,6 +1023,7 @@ FFZ.prototype._modify_room = function(room) {
|
||||||
if ( msg.from === user ) {
|
if ( msg.from === user ) {
|
||||||
if ( f.settings.remove_deleted ) {
|
if ( f.settings.remove_deleted ) {
|
||||||
msgs.removeAt(i);
|
msgs.removeAt(i);
|
||||||
|
removed++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1013,6 +1033,9 @@ FFZ.prototype._modify_room = function(room) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( (removed % 2) && f._roomv && f._roomv.get('context.model.id') === this.get('id') )
|
||||||
|
f._roomv.ffzAlternate();
|
||||||
|
|
||||||
// Delete pending messages
|
// Delete pending messages
|
||||||
if (t.ffzPending) {
|
if (t.ffzPending) {
|
||||||
msgs = t.ffzPending;
|
msgs = t.ffzPending;
|
||||||
|
@ -1064,8 +1087,11 @@ FFZ.prototype._modify_room = function(room) {
|
||||||
len = messages.get("length"),
|
len = messages.get("length"),
|
||||||
limit = this.get("messageBufferSize");
|
limit = this.get("messageBufferSize");
|
||||||
|
|
||||||
if ( len > limit )
|
if ( len > limit ) {
|
||||||
messages.removeAt(0, len - limit);
|
messages.removeAt(0, len - limit);
|
||||||
|
if ( ((len - limit) % 2) && f._roomv && f._roomv.get('context.model.id') === this.get('id') )
|
||||||
|
f._roomv.ffzAlternate();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Artificial chat delay
|
// Artificial chat delay
|
||||||
|
|
124
src/emoticons.js
124
src/emoticons.js
|
@ -4,46 +4,11 @@ var FFZ = window.FrankerFaceZ,
|
||||||
constants = require('./constants'),
|
constants = require('./constants'),
|
||||||
utils = require('./utils'),
|
utils = require('./utils'),
|
||||||
|
|
||||||
|
|
||||||
/*check_margins = function(margins, height) {
|
|
||||||
var mlist = margins.split(/ +/);
|
|
||||||
if ( mlist.length != 2 )
|
|
||||||
return margins;
|
|
||||||
|
|
||||||
mlist[0] = parseFloat(mlist[0]);
|
|
||||||
mlist[1] = parseFloat(mlist[1]);
|
|
||||||
|
|
||||||
if ( mlist[0] == (height - 18) / -2 && mlist[1] == 0 )
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return margins;
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
build_legacy_css = function(emote) {
|
|
||||||
var margin = emote.margins, srcset = "";
|
|
||||||
if ( ! margin )
|
|
||||||
margin = ((emote.height - 18) / -2) + "px 0";
|
|
||||||
|
|
||||||
if ( emote.urls[2] || emote.urls[4] ) {
|
|
||||||
srcset = 'url("' + emote.urls[1] + '") 1x';
|
|
||||||
if ( emote.urls[2] )
|
|
||||||
srcset += ', url("' + emote.urls[2] + '") 2x';
|
|
||||||
if ( emote.urls[4] )
|
|
||||||
srcset += ', url("' + emote.urls[4] + '") 4x';
|
|
||||||
|
|
||||||
srcset = '-webkit-image-set(' + srcset + '); image-set(' + srcset + ');';
|
|
||||||
}
|
|
||||||
|
|
||||||
return ".ffz-emote-" + emote.id + ' { background-image: url("' + emote.urls[1] + '"); height: ' + emote.height + "px; width: " + emote.width + "px; margin: " + margin + (srcset ? '; ' + srcset : '') + (emote.css ? "; " + emote.css : "") + "}\n";
|
|
||||||
},*/
|
|
||||||
|
|
||||||
|
|
||||||
build_css = function(emote) {
|
build_css = function(emote) {
|
||||||
if ( ! emote.margins && ! emote.css )
|
if ( ! emote.margins && ! emote.css )
|
||||||
return ""; //build_legacy_css(emote);
|
return "";
|
||||||
|
|
||||||
return /*build_legacy_css(emote) +*/ 'img[src="' + emote.urls[1] + '"] { ' + (emote.margins ? "margin: " + emote.margins + ";" : "") + (emote.css || "") + " }\n";
|
return 'img[src="' + emote.urls[1] + '"] { ' + (emote.margins ? "margin: " + emote.margins + ";" : "") + (emote.css || "") + " }\n";
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
@ -120,8 +85,15 @@ FFZ.prototype.setup_emoticons = function() {
|
||||||
// Emote Usage
|
// Emote Usage
|
||||||
// ------------------------
|
// ------------------------
|
||||||
|
|
||||||
FFZ.prototype.add_usage = function(room_id, emote_id, count) {
|
FFZ.prototype.add_usage = function(room_id, emote, count) {
|
||||||
var rooms = this.emote_usage[emote_id] = this.emote_usage[emote_id] || {};
|
// Only report usage from FFZ emotes. Not extensions to FFZ.
|
||||||
|
var emote_set = this.emote_sets[emote.set_id];
|
||||||
|
if ( ! emote_set || emote_set.source_ext )
|
||||||
|
return;
|
||||||
|
|
||||||
|
var emote_id = emote.id,
|
||||||
|
rooms = this.emote_usage[emote_id] = this.emote_usage[emote_id] || {};
|
||||||
|
|
||||||
rooms[room_id] = (rooms[room_id] || 0) + (count || 1);
|
rooms[room_id] = (rooms[room_id] || 0) + (count || 1);
|
||||||
|
|
||||||
if ( this._emote_report_scheduled )
|
if ( this._emote_report_scheduled )
|
||||||
|
@ -260,12 +232,82 @@ FFZ.prototype._emote_tooltip = function(emote) {
|
||||||
var set = this.emote_sets[emote.set_id],
|
var set = this.emote_sets[emote.set_id],
|
||||||
owner = emote.owner,
|
owner = emote.owner,
|
||||||
title = set && set.title || "Global",
|
title = set && set.title || "Global",
|
||||||
source = set && set.source || "FFZ";
|
source = set && set.source || "FFZ",
|
||||||
|
|
||||||
emote._tooltip = "Emoticon: " + (emote.hidden ? "???" : emote.name) + "<br>" + source + " " + title + (owner ? "<br>By: " + owner.display_name : "");
|
preview_url = this.settings.emote_image_hover ? (emote.urls[4] || emote.urls[2]) : null,
|
||||||
|
image = preview_url ? '<img class="emoticon ffz-image-hover" src="' + preview_url + '?_=preview">' : '';
|
||||||
|
|
||||||
|
emote._tooltip = image + "Emoticon: " + (emote.hidden ? "???" : emote.name) + "<br>" + source + " " + title + (owner ? "<br>By: " + owner.display_name : "");
|
||||||
return emote._tooltip;
|
return emote._tooltip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FFZ.prototype._reset_tooltips = function(twitch_only) {
|
||||||
|
for(var emote_id in this._twitch_emotes) {
|
||||||
|
var data = this._twitch_emotes[emote_id];
|
||||||
|
if ( data && data.tooltip )
|
||||||
|
data.tooltip = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! twitch_only ) {
|
||||||
|
for(var set_id in this.emote_sets) {
|
||||||
|
var emote_set = this.emote_sets[set_id];
|
||||||
|
for(var emote_id in emote_set.emoticons) {
|
||||||
|
var emote = emote_set.emoticons[emote_id];
|
||||||
|
if ( emote._tooltip )
|
||||||
|
emote._tooltip = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var emotes = document.querySelectorAll('img.emoticon');
|
||||||
|
for(var i=0; i < emotes.length; i++) {
|
||||||
|
var emote = emotes[i];
|
||||||
|
if ( emote.classList.contains('ffz-image-hover') )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var set_id,
|
||||||
|
emote_id = emote.getAttribute('data-emote');
|
||||||
|
|
||||||
|
if ( emote_id ) {
|
||||||
|
// Twitch Emotes
|
||||||
|
if ( this.has_bttv )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
emote.setAttribute('original-title', utils.build_tooltip.bind(this)(emote_id, false, emote.alt));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( twitch_only )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// FFZ Emoji
|
||||||
|
emote_id = emote.getAttribute('data-ffz-emoji');
|
||||||
|
if ( emote_id ) {
|
||||||
|
var emoji = this.emoji_data && this.emoji_data[emote_id],
|
||||||
|
setting = this.settings.parse_emoji,
|
||||||
|
|
||||||
|
src = emoji ? (setting === 2 ? emoji.noto_src : emoji.tw_src) : null,
|
||||||
|
image = '';
|
||||||
|
|
||||||
|
if ( src && this.settings.emote_image_hover )
|
||||||
|
image = '<img class="emoticon ffz-image-hover emoji" src="' + src + '">';
|
||||||
|
|
||||||
|
emote.setAttribute('original-title', emoji ? (image + 'Emoji: ' + emote.alt + '<br>Name: ' + emoji.name + (emoji.short_name ? "<br>Short Name: :" + emoji.short_name + ":" : "")) : emote.alt);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FFZ Emotes
|
||||||
|
emote_id = emote.getAttribute('data-ffz-emote');
|
||||||
|
set_id = emote.getAttribute('data-ffz-set');
|
||||||
|
|
||||||
|
var emote_set = this.emote_sets[set_id];
|
||||||
|
if ( ! emote_set || ! emote_set.emoticons || ! emote_set.emoticons[emote_id] )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
emote.setAttribute('original-title', this._emote_tooltip(emote_set.emoticons[emote_id]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ---------------------
|
// ---------------------
|
||||||
// Emoji Loading
|
// Emoji Loading
|
||||||
|
|
|
@ -25,8 +25,6 @@ FFZ.prototype.setup_bttv = function(delay) {
|
||||||
this.log("BetterTTV was detected after " + delay + "ms. Hooking.");
|
this.log("BetterTTV was detected after " + delay + "ms. Hooking.");
|
||||||
this.has_bttv = true;
|
this.has_bttv = true;
|
||||||
|
|
||||||
// this.track('setCustomVariable', '3', 'BetterTTV', BetterTTV.info.versionString());
|
|
||||||
|
|
||||||
// Disable Dark if it's enabled.
|
// Disable Dark if it's enabled.
|
||||||
document.body.classList.remove("ffz-dark");
|
document.body.classList.remove("ffz-dark");
|
||||||
if ( this._dark_style ) {
|
if ( this._dark_style ) {
|
||||||
|
@ -224,14 +222,14 @@ FFZ.prototype.setup_bttv = function(delay) {
|
||||||
// Why is emote parsing so bad? ;_;
|
// Why is emote parsing so bad? ;_;
|
||||||
_.each(emotes, function(emote) {
|
_.each(emotes, function(emote) {
|
||||||
var tooltip = f._emote_tooltip(emote),
|
var tooltip = f._emote_tooltip(emote),
|
||||||
eo = ['<img class="emoticon" data-ffz-emote="' + emote.id + '" srcset="' + (emote.srcSet || "") + '" src="' + emote.urls[1] + '" data-regex="' + emote.name + '" title="' + tooltip + '" />'],
|
eo = ['<img class="emoticon html-tooltip" data-ffz-emote="' + emote.id + '" srcset="' + utils.quote_attr(emote.srcSet || "") + '" src="' + utils.quote_attr(emote.urls[1]) + '" data-regex="' + utils.quote_attr(emote.name) + '" title="' + utils.quote_attr(tooltip) + '">'],
|
||||||
old_tokens = tokens;
|
old_tokens = tokens;
|
||||||
|
|
||||||
tokens = [];
|
tokens = [];
|
||||||
|
|
||||||
for(var i=0; i < old_tokens.length; i++) {
|
for(var i=0; i < old_tokens.length; i++) {
|
||||||
var token = old_tokens[i];
|
var token = old_tokens[i];
|
||||||
if ( typeof token != "string" ) {
|
if ( typeof token !== "string" ) {
|
||||||
tokens.push(token);
|
tokens.push(token);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -248,7 +246,7 @@ FFZ.prototype.setup_bttv = function(delay) {
|
||||||
tokens.push(eo);
|
tokens.push(eo);
|
||||||
|
|
||||||
if ( mine && l_room )
|
if ( mine && l_room )
|
||||||
f.add_usage(l_room, emote.id);
|
f.add_usage(l_room, emote);
|
||||||
|
|
||||||
} else
|
} else
|
||||||
tokens.push(bit);
|
tokens.push(bit);
|
||||||
|
@ -258,9 +256,10 @@ FFZ.prototype.setup_bttv = function(delay) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sneak in Emojicon Processing
|
// Sneak in Emojicon Processing
|
||||||
/*
|
|
||||||
if ( f.settings.parse_emoji && f.emoji_data ) {
|
if ( f.settings.parse_emoji && f.emoji_data ) {
|
||||||
var old_tokens = tokens;
|
var old_tokens = tokens,
|
||||||
|
setting = f.settings.parse_emoji;
|
||||||
|
|
||||||
tokens = [];
|
tokens = [];
|
||||||
|
|
||||||
for(var i=0; i < old_tokens.length; i++) {
|
for(var i=0; i < old_tokens.length; i++) {
|
||||||
|
@ -280,20 +279,25 @@ FFZ.prototype.setup_bttv = function(delay) {
|
||||||
variant = tbits.shift();
|
variant = tbits.shift();
|
||||||
|
|
||||||
if ( variant === '\uFE0E' )
|
if ( variant === '\uFE0E' )
|
||||||
bits.push(match);
|
tokens.push(match);
|
||||||
else {
|
else {
|
||||||
var eid = utils.emoji_to_codepoint(match, variant),
|
var eid = utils.emoji_to_codepoint(match, variant),
|
||||||
data = f.emoji_data[eid];
|
data = f.emoji_data[eid],
|
||||||
|
src = data && (setting === 2 ? data.noto_src : data.tw_src);
|
||||||
|
|
||||||
if ( data ) {
|
if ( data && src ) {
|
||||||
tokens.push(['<img class="emoticon" height="18px" srcset="' + (data.srcSet || "") + '" src="' + data.src + '" alt="' + alt + '" title="Emoji: ' + data.raw + '\nName: :' + data.short_name + ':">']);
|
var image = src && f.settings.emote_image_hover ? '<img class="emoticon ffz-image-hover" src="' + src + '">' : '',
|
||||||
|
tooltip = image + "Emoji: " + data.raw + "<br>Name: " + data.name + (data.short_name ? "<br>Short Name: :" + data.short_name + ":" : ""),
|
||||||
|
code = utils.quote_attr(data.raw);
|
||||||
|
|
||||||
|
tokens.push(['<img class="emoticon emoji html-tooltip" height="18px" data-ffz-emoji="' + eid + '" src="' + utils.quote_attr(src) + '" data-regex="' + code + '" alt="' + code + '" title="' + utils.quote_attr(tooltip) + '">']);
|
||||||
} else
|
} else
|
||||||
tokens.push(match + (variant || ""));
|
tokens.push(match + (variant || ""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
|
|
||||||
return tokens;
|
return tokens;
|
||||||
}
|
}
|
||||||
|
|
277
src/ext/rechat.js
Normal file
277
src/ext/rechat.js
Normal file
|
@ -0,0 +1,277 @@
|
||||||
|
var FFZ = window.FrankerFaceZ,
|
||||||
|
constants = require('../constants'),
|
||||||
|
utils = require('../utils');
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------
|
||||||
|
// Initialization
|
||||||
|
// --------------------
|
||||||
|
|
||||||
|
FFZ.prototype.setup_rechat = function() {
|
||||||
|
if ( this.has_bttv || navigator.userAgent.indexOf('Android') !== -1 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._rechat_listening = false;
|
||||||
|
|
||||||
|
this.log("Installing ReChat mutation observer.");
|
||||||
|
|
||||||
|
var f = this;
|
||||||
|
this._rechat_observer = new MutationObserver(function(mutations) {
|
||||||
|
for(var i=0; i < mutations.length; i++) {
|
||||||
|
var mutation = mutations[i];
|
||||||
|
if ( mutation.type !== "childList" )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for(var x=0; x < mutation.addedNodes.length; x++) {
|
||||||
|
var added = mutation.addedNodes[x];
|
||||||
|
if ( added.nodeType !== added.ELEMENT_NODE || added.tagName !== "DIV" )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Is this a ReChat line?
|
||||||
|
if ( added.classList.contains('rechat-chat-line') && ! added.classList.contains('ffz-processed') )
|
||||||
|
f.process_rechat_line(added);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.log("Starting ReChat check loop.");
|
||||||
|
this._rechat_interval = setInterval(this.find_rechat.bind(this), 1000);
|
||||||
|
this.find_rechat();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------
|
||||||
|
// ReChat Detection
|
||||||
|
// --------------------
|
||||||
|
|
||||||
|
FFZ.prototype.find_rechat = function() {
|
||||||
|
var el = !this.has_bttv ? document.querySelector('.rechat-chat-line') : null;
|
||||||
|
|
||||||
|
// If there's no change, don't continue.
|
||||||
|
if ( !!el === this._rechat_listening )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If we're no longer listening, stop the observer and quit.
|
||||||
|
if ( ! el ) {
|
||||||
|
this._rechat_observer.disconnect();
|
||||||
|
this._rechat_listening = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're newly listening. Process all existing ReChat chat lines
|
||||||
|
// and darken the container if required, also enable the observer.
|
||||||
|
var container = jQuery(el).parents('.chat-container');
|
||||||
|
if ( ! container.length )
|
||||||
|
return;
|
||||||
|
|
||||||
|
container = container[0];
|
||||||
|
|
||||||
|
// Look-up dark mode.
|
||||||
|
var dark_chat = this.settings.dark_twitch;
|
||||||
|
if ( ! dark_chat ) {
|
||||||
|
var model = window.App ? App.__container__.lookup('controller:settings').get('model') : undefined;
|
||||||
|
dark_chat = model && model.get('darkMode');
|
||||||
|
}
|
||||||
|
|
||||||
|
container.classList.toggle('dark', dark_chat);
|
||||||
|
jQuery(container).find('.chat-lines').addClass('ffz-scrollbar');
|
||||||
|
|
||||||
|
// Tooltips
|
||||||
|
jQuery(container).find('.tooltip').tipsy({live: true, gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
|
||||||
|
jQuery(container).find('.html-tooltip').tipsy({live: true, html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
|
||||||
|
|
||||||
|
// Load the room data.
|
||||||
|
var room_id = el.getAttribute('data-room');
|
||||||
|
if ( room_id && ! this.rooms[room_id] )
|
||||||
|
this.load_room(room_id, this._reprocess_rechat.bind(this, container));
|
||||||
|
|
||||||
|
// Do stuff.
|
||||||
|
var lines = container.querySelectorAll('.rechat-chat-line');
|
||||||
|
for(var i=0; i < lines.length; i++) {
|
||||||
|
var line = lines[i];
|
||||||
|
if ( line.classList.contains('ffz-processed') )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
this.process_rechat_line(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start observing.
|
||||||
|
this._rechat_observer.observe(container, {
|
||||||
|
childList: true,
|
||||||
|
subtree: true
|
||||||
|
});
|
||||||
|
|
||||||
|
this._rechat_listening = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------
|
||||||
|
// ReChat Lines
|
||||||
|
// --------------------
|
||||||
|
|
||||||
|
FFZ.prototype._reprocess_rechat = function(container) {
|
||||||
|
var lines = container.querySelectorAll('.rechat-chat-line');
|
||||||
|
for(var i=0; i < lines.length; i++)
|
||||||
|
this.process_rechat_line(lines[i], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FFZ.prototype.process_rechat_line = function(line, reprocess) {
|
||||||
|
if ( ! reprocess && line.classList.contains('ffz-processed') )
|
||||||
|
return;
|
||||||
|
|
||||||
|
line.classList.add('ffz-processed');
|
||||||
|
|
||||||
|
var user_id = line.getAttribute('data-sender'),
|
||||||
|
room_id = line.getAttribute('data-room'),
|
||||||
|
|
||||||
|
Layout = App.__container__.lookup('controller:layout'),
|
||||||
|
Settings = App.__container__.lookup('controller:settings'),
|
||||||
|
is_dark = (Layout && Layout.get('isTheatreMode')) || (Settings && Settings.get('model.darkMode')),
|
||||||
|
|
||||||
|
badges_el = line.querySelector('.badges'),
|
||||||
|
from_el = line.querySelector('.from'),
|
||||||
|
message_el = line.querySelector('.message'),
|
||||||
|
|
||||||
|
badges = {},
|
||||||
|
had_badges = !!badges_el,
|
||||||
|
|
||||||
|
raw_color = from_el && FFZ.Color.RGB.fromCSS(from_el.style.color),
|
||||||
|
colors = raw_color && this._handle_color(raw_color),
|
||||||
|
|
||||||
|
alias = this.aliases[user_id];
|
||||||
|
|
||||||
|
|
||||||
|
if ( ! badges_el ) {
|
||||||
|
badges_el = document.createElement('span');
|
||||||
|
badges_el.className = 'badges float-left';
|
||||||
|
line.insertBefore(badges_el, from_el || line.firstElementChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! reprocess || ! had_badges ) {
|
||||||
|
// Read existing known badges.
|
||||||
|
var existing = badges_el.querySelectorAll('.badge');
|
||||||
|
for(var i=0; i < existing.length; i++) {
|
||||||
|
var badge = existing[i];
|
||||||
|
if ( badge.classList.contains('broadcaster') )
|
||||||
|
badges[0] = {klass: 'broadcaster', title: 'Broadcaster'};
|
||||||
|
else if ( badge.classList.contains('staff') )
|
||||||
|
badges[0] = {klass: 'staff', title: 'Staff'};
|
||||||
|
else if ( badge.classList.contains('admin') )
|
||||||
|
badges[0] = {klass: 'admin', title: 'Admin'};
|
||||||
|
else if ( badge.classList.contains('global-moderator') )
|
||||||
|
badges[0] = {klass: 'global-moderator', title: 'Global Moderator'};
|
||||||
|
else if ( badge.classList.contains('moderator') )
|
||||||
|
badges[0] = {klass: 'moderator', title: 'Moderator'};
|
||||||
|
else if ( badge.classList.contains('subscriber') )
|
||||||
|
badges[10] = {klass: 'subscriber', title: 'Subscriber'};
|
||||||
|
else if ( badge.classList.contains('turbo') )
|
||||||
|
badges[15] = {klass: 'turbo', title: 'Turbo'};
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( user_id && user_id === room_id )
|
||||||
|
badges[0] = {klass: 'broadcaster', title: 'Broadcaster'};
|
||||||
|
|
||||||
|
if ( user_id )
|
||||||
|
badges = this._render_badges(user_id, room_id, badges);
|
||||||
|
|
||||||
|
var output = '';
|
||||||
|
for(var key in badges) {
|
||||||
|
var badge = badges[key],
|
||||||
|
css = badge.iamge ? 'background-image:url("' + badge.image + '");' : '';
|
||||||
|
|
||||||
|
if ( badge.color )
|
||||||
|
css += 'background-color:' + badge.color + ';';
|
||||||
|
|
||||||
|
if ( badge.extra_css )
|
||||||
|
css += badge.extra_css;
|
||||||
|
|
||||||
|
output += '<div class="badge float-left tooltip ' + badge.klass + '"' + (css ? ' style="' + css + '"' : '') + ' title="' + badge.title + '"></div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
badges_el.innerHTML = output;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! reprocess && from_el ) {
|
||||||
|
from_el.style.fontWeight = "";
|
||||||
|
if ( colors ) {
|
||||||
|
from_el.classList.add('has_color');
|
||||||
|
from_el.style.color = is_dark ? colors[1] : colors[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( alias ) {
|
||||||
|
from_el.classList.add('ffz-alias');
|
||||||
|
from_el.title = from_el.textContent;
|
||||||
|
from_el.textContent = alias;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! message_el )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( ! reprocess && message_el.style.color ) {
|
||||||
|
message_el.classList.add('has-color');
|
||||||
|
message_el.style.color = is_dark ? colors[1] : colors[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
var raw_tokens = line.getAttribute('data-tokens'),
|
||||||
|
tokens = raw_tokens ? JSON.parse(raw_tokens) : [];
|
||||||
|
|
||||||
|
if ( ! raw_tokens ) {
|
||||||
|
for(var i=0; i < message_el.childNodes.length; i++) {
|
||||||
|
var node = message_el.childNodes[i];
|
||||||
|
|
||||||
|
if ( node.nodeType === node.TEXT_NODE )
|
||||||
|
tokens.push(node.textContent);
|
||||||
|
|
||||||
|
else if ( node.nodeType === node.ELEMENT_NODE ) {
|
||||||
|
if ( node.tagName === 'IMG' )
|
||||||
|
tokens.push({
|
||||||
|
altText: node.alt,
|
||||||
|
emoticonSrc: node.src
|
||||||
|
});
|
||||||
|
|
||||||
|
else if ( node.tagName === 'A' )
|
||||||
|
tokens.push({
|
||||||
|
isLink: true,
|
||||||
|
href: node.textContent
|
||||||
|
});
|
||||||
|
|
||||||
|
else if ( node.tagName === 'SPAN' )
|
||||||
|
tokens.push({
|
||||||
|
mentionedUser: node.textContent,
|
||||||
|
own: node.classList.contains('mentioning')
|
||||||
|
});
|
||||||
|
|
||||||
|
else
|
||||||
|
this.log("Unknown Tag Type: " + node.tagName);
|
||||||
|
} else
|
||||||
|
this.log("Unknown Node Type Tokenizing Message: " + node.nodeType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
line.setAttribute('data-tokens', JSON.stringify(tokens));
|
||||||
|
|
||||||
|
// Further tokenization~!
|
||||||
|
if ( this.settings.replace_bad_emotes )
|
||||||
|
tokens = this.tokenize_replace_emotes(tokens);
|
||||||
|
|
||||||
|
tokens = this._remove_banned(tokens);
|
||||||
|
tokens = this.tokenize_emotes(user_id, room_id, tokens, false);
|
||||||
|
|
||||||
|
if ( this.settings.parse_emoji )
|
||||||
|
tokens = this.tokenize_emoji(tokens);
|
||||||
|
|
||||||
|
tokens = this.tokenize_mentions(tokens);
|
||||||
|
|
||||||
|
// Check for a mention
|
||||||
|
if ( ! line.classList.contains('ffz-mentioend') )
|
||||||
|
for(var i=0; i < tokens.length; i++)
|
||||||
|
if ( tokens[i].mentionedUser ) {
|
||||||
|
line.classList.add('ffz-mentioned');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, put the content back into the element.
|
||||||
|
message_el.innerHTML = this.render_tokens(tokens);
|
||||||
|
}
|
28
src/main.js
28
src/main.js
|
@ -22,7 +22,7 @@ FFZ.get = function() { return FFZ.instance; }
|
||||||
|
|
||||||
// Version
|
// Version
|
||||||
var VER = FFZ.version_info = {
|
var VER = FFZ.version_info = {
|
||||||
major: 3, minor: 5, revision: 65,
|
major: 3, minor: 5, revision: 77,
|
||||||
toString: function() {
|
toString: function() {
|
||||||
return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || "");
|
return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || "");
|
||||||
}
|
}
|
||||||
|
@ -90,12 +90,22 @@ FFZ.prototype._pastebin = function(data, callback) {
|
||||||
// -------------------
|
// -------------------
|
||||||
|
|
||||||
FFZ.prototype.get_user = function() {
|
FFZ.prototype.get_user = function() {
|
||||||
if ( window.PP && PP.login ) {
|
if ( this.__user )
|
||||||
return PP;
|
return this.__user;
|
||||||
} else if ( window.App ) {
|
|
||||||
var nc = App.__container__.lookup("controller:login");
|
var user;
|
||||||
return nc ? nc.get("userData") : undefined;
|
if ( window.App ) {
|
||||||
|
var nc = App.__container__.lookup('controller:login');
|
||||||
|
user = nc ? nc.get('userData') : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ! user && window.PP && PP.login )
|
||||||
|
user = PP;
|
||||||
|
|
||||||
|
if ( user )
|
||||||
|
this.__user = user;
|
||||||
|
|
||||||
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -133,6 +143,7 @@ require('./ember/following');
|
||||||
|
|
||||||
require('./debug');
|
require('./debug');
|
||||||
|
|
||||||
|
require('./ext/rechat');
|
||||||
require('./ext/betterttv');
|
require('./ext/betterttv');
|
||||||
require('./ext/emote_menu');
|
require('./ext/emote_menu');
|
||||||
|
|
||||||
|
@ -140,6 +151,7 @@ require('./featurefriday');
|
||||||
|
|
||||||
require('./ui/styles');
|
require('./ui/styles');
|
||||||
require('./ui/dark');
|
require('./ui/dark');
|
||||||
|
require('./ui/tooltips');
|
||||||
require('./ui/notifications');
|
require('./ui/notifications');
|
||||||
require('./ui/viewer_count');
|
require('./ui/viewer_count');
|
||||||
require('./ui/sub_count');
|
require('./ui/sub_count');
|
||||||
|
@ -256,6 +268,7 @@ FFZ.prototype.init_normal = function(delay, no_socket) {
|
||||||
this.setup_following_count(false);
|
this.setup_following_count(false);
|
||||||
this.setup_menu();
|
this.setup_menu();
|
||||||
|
|
||||||
|
this.fix_tooltips();
|
||||||
this.find_bttv(10);
|
this.find_bttv(10);
|
||||||
|
|
||||||
var end = (window.performance && performance.now) ? performance.now() : Date.now(),
|
var end = (window.performance && performance.now) ? performance.now() : Date.now(),
|
||||||
|
@ -297,6 +310,7 @@ FFZ.prototype.init_dashboard = function(delay) {
|
||||||
// Set up the FFZ message passer.
|
// Set up the FFZ message passer.
|
||||||
this.setup_message_event();
|
this.setup_message_event();
|
||||||
|
|
||||||
|
this.fix_tooltips();
|
||||||
this.find_bttv(10);
|
this.find_bttv(10);
|
||||||
|
|
||||||
var end = (window.performance && performance.now) ? performance.now() : Date.now(),
|
var end = (window.performance && performance.now) ? performance.now() : Date.now(),
|
||||||
|
@ -354,8 +368,10 @@ FFZ.prototype.init_ember = function(delay) {
|
||||||
this.setup_following_count(true);
|
this.setup_following_count(true);
|
||||||
this.setup_races();
|
this.setup_races();
|
||||||
|
|
||||||
|
this.fix_tooltips();
|
||||||
this.connect_extra_chat();
|
this.connect_extra_chat();
|
||||||
|
|
||||||
|
this.setup_rechat();
|
||||||
this.find_bttv(10);
|
this.find_bttv(10);
|
||||||
this.find_emote_menu(10);
|
this.find_emote_menu(10);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
/* Regular Alternating Background */
|
/* Regular Alternating Background */
|
||||||
.conversation-chat-lines > div:nth-child(2n+0):before,
|
.conversation-chat-lines > div:nth-child(2n+0):before,
|
||||||
.chat-history .chat-line:nth-child(2n+0):before,
|
.chat-history .chat-line:nth-child(2n+0):before,
|
||||||
.ember-chat .chat-lines > div:nth-child(2n+0) .chat-line:before {
|
.ember-chat .chat-lines > div:nth-child(2n+0) .chat-line:before,
|
||||||
|
|
||||||
|
/* ReChat */
|
||||||
|
.ember-chat.chat-messages > .rechat-chat-line:nth-child(2n+0):before {
|
||||||
background-color: rgba(0,0,0, 0.1);
|
background-color: rgba(0,0,0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +20,12 @@
|
||||||
.dark .chat-history .chat-line:nth-child(2n+0):before,
|
.dark .chat-history .chat-line:nth-child(2n+0):before,
|
||||||
.force-dark .chat-history .chat-line:nth-child(2n+0):before,
|
.force-dark .chat-history .chat-line:nth-child(2n+0):before,
|
||||||
.dark .chat-lines > div:nth-child(2n+0) .chat-line:before,
|
.dark .chat-lines > div:nth-child(2n+0) .chat-line:before,
|
||||||
.force-dark .chat-lines > div:nth-child(2n+0) .chat-line:before {
|
.force-dark .chat-lines > div:nth-child(2n+0) .chat-line:before,
|
||||||
|
|
||||||
|
/* ReChat */
|
||||||
|
.theatre .chat-lines > .rechat-chat-line:nth-child(2n+0):before,
|
||||||
|
.dark .chat-lines > .rechat-chat-line:nth-child(2n+0):before,
|
||||||
|
.force-dark .chat-lines > .rechat-chat-line:nth-child(2n+0):before {
|
||||||
background-color: rgba(255,255,255, 0.05);
|
background-color: rgba(255,255,255, 0.05);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* High-Contrast Background */
|
/* High-Contrast Background */
|
||||||
.chat-container,
|
.chat-container,
|
||||||
.ember-chat-container {
|
.ember-chat-container {
|
||||||
background-color: #fff;
|
background-color: #fff !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,5 +12,5 @@
|
||||||
.chat-container.force-dark,
|
.chat-container.force-dark,
|
||||||
.ember-chat-container.dark,
|
.ember-chat-container.dark,
|
||||||
.ember-chat-container.force-dark {
|
.ember-chat-container.force-dark {
|
||||||
background-color: #000;
|
background-color: #000 !important;
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
/* High-Contrast Text */
|
/* High-Contrast Text */
|
||||||
.chat-container,
|
.chat-container,
|
||||||
.ember-chat-container {
|
.ember-chat-container {
|
||||||
color: #000;
|
color: #000 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dark: High-Contrast Text */
|
/* Dark: High-Contrast Text */
|
||||||
|
@ -10,6 +10,10 @@
|
||||||
.chat-container.dark,
|
.chat-container.dark,
|
||||||
.chat-container.force-dark,
|
.chat-container.force-dark,
|
||||||
.ember-chat-container.dark,
|
.ember-chat-container.dark,
|
||||||
.ember-chat-container.force-dark {
|
.ember-chat-container.force-dark,
|
||||||
color: #fff;
|
|
||||||
|
.ffz-dark .ember-chat-container.dark .chat-line,
|
||||||
|
.ffz-dark .chat-container.dark .chat-line
|
||||||
|
{
|
||||||
|
color: #fff !important;
|
||||||
}
|
}
|
116
src/tokenize.js
116
src/tokenize.js
|
@ -1,76 +1,11 @@
|
||||||
var FFZ = window.FrankerFaceZ,
|
var FFZ = window.FrankerFaceZ,
|
||||||
utils = require("./utils"),
|
utils = require("./utils"),
|
||||||
constants = require("./constants"),
|
constants = require("./constants"),
|
||||||
TWITCH_BASE = "http://static-cdn.jtvnw.net/emoticons/v1/",
|
|
||||||
helpers,
|
helpers,
|
||||||
|
conv_helpers,
|
||||||
|
|
||||||
EXPLANATION_TRAIL = '<hr>FFZ is hiding this link because this url shortener is known to be used by Twitch spam bots posting malicious links. Please use caution when visiting shortened links.',
|
EXPLANATION_TRAIL = '<hr>FFZ is hiding this link because this url shortener is known to be used by Twitch spam bots posting malicious links. Please use caution when visiting shortened links.',
|
||||||
|
|
||||||
SRCSETS = {};
|
|
||||||
build_srcset = function(id) {
|
|
||||||
if ( SRCSETS[id] )
|
|
||||||
return SRCSETS[id];
|
|
||||||
var out = SRCSETS[id] = TWITCH_BASE + id + "/1.0 1x, " + TWITCH_BASE + id + "/2.0 2x, " + TWITCH_BASE + id + "/3.0 4x";
|
|
||||||
return out;
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
data_to_tooltip = function(data) {
|
|
||||||
var set = data.set,
|
|
||||||
set_type = data.set_type,
|
|
||||||
owner = data.owner;
|
|
||||||
|
|
||||||
if ( set_type === undefined )
|
|
||||||
set_type = "Channel";
|
|
||||||
|
|
||||||
if ( ! set )
|
|
||||||
return data.code;
|
|
||||||
|
|
||||||
else if ( set === "--global--" ) {
|
|
||||||
set = "Twitch Global";
|
|
||||||
set_type = null;
|
|
||||||
|
|
||||||
} else if ( set == "--twitch-turbo--" || set == "turbo" || set == "--turbo-faces--" ) {
|
|
||||||
set = "Twitch Turbo";
|
|
||||||
set_type = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return "Emoticon: " + data.code + "<br>" + (set_type ? set_type + ": " : "") + set + (owner ? "<br>By: " + owner.display_name : "");
|
|
||||||
},
|
|
||||||
|
|
||||||
build_tooltip = function(id) {
|
|
||||||
var emote_data = this._twitch_emotes[id],
|
|
||||||
set = emote_data ? emote_data.set : null;
|
|
||||||
|
|
||||||
if ( ! emote_data )
|
|
||||||
return "???";
|
|
||||||
|
|
||||||
if ( typeof emote_data == "string" )
|
|
||||||
return emote_data;
|
|
||||||
|
|
||||||
if ( emote_data.tooltip )
|
|
||||||
return emote_data.tooltip;
|
|
||||||
|
|
||||||
return emote_data.tooltip = data_to_tooltip(emote_data);
|
|
||||||
},
|
|
||||||
|
|
||||||
load_emote_data = function(id, code, success, data) {
|
|
||||||
if ( ! success )
|
|
||||||
return code;
|
|
||||||
|
|
||||||
if ( code )
|
|
||||||
data.code = code;
|
|
||||||
|
|
||||||
this._twitch_emotes[id] = data;
|
|
||||||
var tooltip = build_tooltip.bind(this)(id);
|
|
||||||
|
|
||||||
var images = document.querySelectorAll('img[data-emote="' + id + '"]');
|
|
||||||
for(var x=0; x < images.length; x++)
|
|
||||||
images[x].title = tooltip;
|
|
||||||
|
|
||||||
return tooltip;
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
reg_escape = function(str) {
|
reg_escape = function(str) {
|
||||||
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
||||||
|
@ -105,7 +40,7 @@ var FFZ = window.FrankerFaceZ,
|
||||||
return IMGUR_PATH.test(path);
|
return IMGUR_PATH.test(path);
|
||||||
|
|
||||||
return any_domain ? IMAGE_EXT.test(path) : IMAGE_DOMAINS.indexOf(domain) !== -1;
|
return any_domain ? IMAGE_EXT.test(path) : IMAGE_DOMAINS.indexOf(domain) !== -1;
|
||||||
}
|
},
|
||||||
|
|
||||||
image_iframe = function(href, extra_class) {
|
image_iframe = function(href, extra_class) {
|
||||||
return '<iframe class="ffz-image-hover' + (extra_class ? ' ' + extra_class : '') + '" allowtransparency="true" src="' + constants.SERVER + 'script/img-proxy.html#' + utils.quote_attr(href) + '"></iframe>';
|
return '<iframe class="ffz-image-hover' + (extra_class ? ' ' + extra_class : '') + '" allowtransparency="true" src="' + constants.SERVER + 'script/img-proxy.html#' + utils.quote_attr(href) + '"></iframe>';
|
||||||
|
@ -248,12 +183,12 @@ FFZ._emote_mirror_swap = function(img) {
|
||||||
img.setAttribute('data-alt-attempts', attempts + 1);
|
img.setAttribute('data-alt-attempts', attempts + 1);
|
||||||
var id = img.getAttribute('data-emote');
|
var id = img.getAttribute('data-emote');
|
||||||
|
|
||||||
if ( img.src.substr(0, TWITCH_BASE.length) === TWITCH_BASE ) {
|
if ( img.src.substr(0, constants.TWITCH_BASE.length) === constants.TWITCH_BASE ) {
|
||||||
img.src = constants.EMOTE_MIRROR_BASE + id + ".png";
|
img.src = constants.EMOTE_MIRROR_BASE + id + ".png";
|
||||||
img.srcset = "";
|
img.srcset = "";
|
||||||
} else {
|
} else {
|
||||||
img.src = TWITCH_BASE + id + "/1.0";
|
img.src = constants.TWITCH_BASE + id + "/1.0";
|
||||||
img.srcset = build_srcset(id);
|
img.srcset = utils.build_srcset(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,6 +252,10 @@ FFZ.prototype.setup_tokenization = function() {
|
||||||
if ( ! helpers )
|
if ( ! helpers )
|
||||||
return this.log("Unable to get chat helper functions.");
|
return this.log("Unable to get chat helper functions.");
|
||||||
|
|
||||||
|
conv_helpers = window.require && window.require("ember-twitch-conversations/helpers/conversation-line-helpers");
|
||||||
|
if ( ! conv_helpers )
|
||||||
|
this.log("Unable to get conversation helper functions.");
|
||||||
|
|
||||||
this.log("Hooking Ember chat line helpers.");
|
this.log("Hooking Ember chat line helpers.");
|
||||||
|
|
||||||
var f = this;
|
var f = this;
|
||||||
|
@ -386,6 +325,8 @@ FFZ.prototype.load_twitch_emote_data = function(tries) {
|
||||||
this._twitch_set_to_channel[33] = "--turbo-faces--";
|
this._twitch_set_to_channel[33] = "--turbo-faces--";
|
||||||
this._twitch_set_to_channel[42] = "--turbo-faces--";
|
this._twitch_set_to_channel[42] = "--turbo-faces--";
|
||||||
|
|
||||||
|
this._reset_tooltips(true);
|
||||||
|
|
||||||
}).fail(function(data) {
|
}).fail(function(data) {
|
||||||
if ( data.status === 404 )
|
if ( data.status === 404 )
|
||||||
return;
|
return;
|
||||||
|
@ -410,6 +351,9 @@ FFZ.prototype.tokenize_conversation_line = function(message, prevent_notificatio
|
||||||
emotes = message.get('tags.emotes'),
|
emotes = message.get('tags.emotes'),
|
||||||
tokens = [msg];
|
tokens = [msg];
|
||||||
|
|
||||||
|
if ( conv_helpers && conv_helpers.checkActionMessage )
|
||||||
|
tokens = conv_helpers.checkActionMessage(tokens);
|
||||||
|
|
||||||
// Standard Tokenization
|
// Standard Tokenization
|
||||||
if ( helpers && helpers.linkifyMessage )
|
if ( helpers && helpers.linkifyMessage )
|
||||||
tokens = helpers.linkifyMessage(tokens);
|
tokens = helpers.linkifyMessage(tokens);
|
||||||
|
@ -597,8 +541,11 @@ FFZ.prototype.tokenize_line = function(user, room, message, no_emotes, no_emoji)
|
||||||
FFZ.prototype.render_tokens = function(tokens, render_links) {
|
FFZ.prototype.render_tokens = function(tokens, render_links) {
|
||||||
var f = this;
|
var f = this;
|
||||||
return _.map(tokens, function(token) {
|
return _.map(tokens, function(token) {
|
||||||
|
if ( token.hidden )
|
||||||
|
return "";
|
||||||
|
|
||||||
if ( token.emoticonSrc ) {
|
if ( token.emoticonSrc ) {
|
||||||
var tooltip, src = token.emoticonSrc, srcset, extra;
|
var tooltip, src = token.emoticonSrc, srcset, cls, extra;
|
||||||
if ( token.ffzEmote ) {
|
if ( token.ffzEmote ) {
|
||||||
var emote_set = f.emote_sets && f.emote_sets[token.ffzEmoteSet],
|
var emote_set = f.emote_sets && f.emote_sets[token.ffzEmoteSet],
|
||||||
emote = emote_set && emote_set.emoticons && emote_set.emoticons[token.ffzEmote];
|
emote = emote_set && emote_set.emoticons && emote_set.emoticons[token.ffzEmote];
|
||||||
|
@ -610,26 +557,32 @@ FFZ.prototype.render_tokens = function(tokens, render_links) {
|
||||||
} else if ( token.ffzEmoji ) {
|
} else if ( token.ffzEmoji ) {
|
||||||
var eid = token.ffzEmoji,
|
var eid = token.ffzEmoji,
|
||||||
emoji = f.emoji_data && f.emoji_data[eid],
|
emoji = f.emoji_data && f.emoji_data[eid],
|
||||||
setting = f.settings.parse_emoji;
|
setting = f.settings.parse_emoji,
|
||||||
|
image = '';
|
||||||
|
|
||||||
if ( setting === 0 || (setting === 1 && ! emoji.tw) || (setting === 2 && ! emoji.noto) )
|
if ( setting === 0 || (setting === 1 && ! emoji.tw) || (setting === 2 && ! emoji.noto) )
|
||||||
return token.altText;
|
return token.altText;
|
||||||
|
|
||||||
tooltip = emoji ? "Emoji: " + token.altText + "\nName: " + emoji.name + (emoji.short_name ? "\nShort Name: :" + emoji.short_name + ":" : "") : token.altText;
|
|
||||||
extra = ' data-ffz-emoji="' + eid + '" height="18px"';
|
|
||||||
src = setting === 2 ? token.noto_src : token.tw_src;
|
src = setting === 2 ? token.noto_src : token.tw_src;
|
||||||
|
|
||||||
|
if ( emoji && f.settings.emote_image_hover )
|
||||||
|
image = '<img class="emoticon ffz-image-hover" src="' + src + '">';
|
||||||
|
|
||||||
|
tooltip = emoji ? image + "Emoji: " + token.altText + "<br>Name: " + emoji.name + (emoji.short_name ? "<br>Short Name: :" + emoji.short_name + ":" : "") : token.altText;
|
||||||
|
extra = ' data-ffz-emoji="' + eid + '" height="18px"';
|
||||||
|
cls = ' emoji';
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
var id = token.replacedId || FFZ.src_to_id(token.emoticonSrc),
|
var id = token.replacedId || FFZ.src_to_id(token.emoticonSrc),
|
||||||
data = id && f._twitch_emotes && f._twitch_emotes[id];
|
data = id && f._twitch_emotes && f._twitch_emotes[id];
|
||||||
|
|
||||||
if ( data )
|
if ( data )
|
||||||
tooltip = data.tooltip ? data.tooltip : token.altText;
|
tooltip = data.tooltip ? data.tooltip : utils.build_tooltip.bind(f)(id, false, token.altText);
|
||||||
else {
|
else {
|
||||||
try {
|
try {
|
||||||
var set_id = f._twitch_emote_to_set[id];
|
var set_id = f._twitch_emote_to_set[id];
|
||||||
if ( set_id ) {
|
if ( set_id ) {
|
||||||
tooltip = load_emote_data.bind(f)(id, token.altText, true, {
|
tooltip = utils.load_emote_data.bind(f)(id, token.altText, true, {
|
||||||
code: token.altText,
|
code: token.altText,
|
||||||
id: id,
|
id: id,
|
||||||
set: f._twitch_set_to_channel[set_id],
|
set: f._twitch_set_to_channel[set_id],
|
||||||
|
@ -637,19 +590,18 @@ FFZ.prototype.render_tokens = function(tokens, render_links) {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
tooltip = f._twitch_emotes[id] = token.altText;
|
tooltip = f._twitch_emotes[id] = token.altText;
|
||||||
f.ws_send("twitch_emote", id, load_emote_data.bind(f, id, token.altText));
|
f.ws_send("twitch_emote", id, utils.load_emote_data.bind(f, id, token.altText));
|
||||||
}
|
}
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
f.error("Error Generating Emote Tooltip: " + err);
|
f.error("Error Generating Emote Tooltip: " + err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var mirror_url = utils.quote_attr(constants.EMOTE_MIRROR_BASE + id + '.png');
|
//var mirror_url = utils.quote_attr(constants.EMOTE_MIRROR_BASE + id + '.png');
|
||||||
|
|
||||||
extra = ' data-emote="' + id + '"'; // onerror="FrankerFaceZ._emote_mirror_swap(this)"'; // Disable error checking for now.
|
extra = ' data-emote="' + id + '"'; // onerror="FrankerFaceZ._emote_mirror_swap(this)"'; // Disable error checking for now.
|
||||||
|
|
||||||
if ( ! constants.EMOTE_REPLACEMENTS[id] )
|
if ( ! constants.EMOTE_REPLACEMENTS[id] )
|
||||||
srcset = build_srcset(id);
|
srcset = utils.build_srcset(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return '<img class="emoticon html-tooltip' + (cls||"") + '"' + (extra||"") + ' src="' + utils.quote_attr(src) + '" ' + (srcset ? 'srcset="' + utils.quote_attr(srcset) + '" ' : '') + 'alt="' + utils.quote_attr(token.altText) + '" title="' + utils.quote_attr(tooltip) + '">';
|
return '<img class="emoticon html-tooltip' + (cls||"") + '"' + (extra||"") + ' src="' + utils.quote_attr(src) + '" ' + (srcset ? 'srcset="' + utils.quote_attr(srcset) + '" ' : '') + 'alt="' + utils.quote_attr(token.altText) + '" title="' + utils.quote_attr(tooltip) + '">';
|
||||||
|
@ -797,7 +749,7 @@ FFZ.prototype.tokenize_title_emotes = function(tokens) {
|
||||||
data = data.emoticon_sets[0];
|
data = data.emoticon_sets[0];
|
||||||
for(var i=0; i < data.length; i++) {
|
for(var i=0; i < data.length; i++) {
|
||||||
var em = data[i];
|
var em = data[i];
|
||||||
emotes.push({regex: em.code, url: TWITCH_BASE + em.id + "/1.0"});
|
emotes.push({regex: em.code, url: utils.TWITCH_BASE + em.id + "/1.0"});
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( f._cindex )
|
if ( f._cindex )
|
||||||
|
@ -893,7 +845,7 @@ FFZ.prototype.tokenize_emotes = function(user, room, tokens, do_report) {
|
||||||
bits.push(eo);
|
bits.push(eo);
|
||||||
|
|
||||||
if ( do_report && room )
|
if ( do_report && room )
|
||||||
f.add_usage(room, emote.id);
|
f.add_usage(room, emote);
|
||||||
|
|
||||||
} else
|
} else
|
||||||
bits.push(bit);
|
bits.push(bit);
|
||||||
|
|
|
@ -144,6 +144,9 @@ FFZ.settings_info.dark_twitch = {
|
||||||
model && model.set('darkMode', true);
|
model && model.set('darkMode', true);
|
||||||
} else
|
} else
|
||||||
model && model.set('darkMode', this.settings.twitch_chat_dark);
|
model && model.set('darkMode', this.settings.twitch_chat_dark);
|
||||||
|
|
||||||
|
// Try coloring ReChat
|
||||||
|
jQuery('.rechat-chat-line').parents('.chat-container').toggleClass('dark', val || this.settings.twitch_chat_dark);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ FFZ.prototype.setup_following_count = function(has_ember) {
|
||||||
|
|
||||||
// If we don't have Ember, no point in trying this stuff.
|
// If we don't have Ember, no point in trying this stuff.
|
||||||
if ( ! has_ember )
|
if ( ! has_ember )
|
||||||
return this._update_following_count();
|
return this._following_get_me();
|
||||||
|
|
||||||
this.log("Connecting to Live Streams model.");
|
this.log("Connecting to Live Streams model.");
|
||||||
var Stream = window.App && App.__container__.resolve('model:stream');
|
var Stream = window.App && App.__container__.resolve('model:stream');
|
||||||
|
@ -80,6 +80,27 @@ FFZ.prototype.setup_following_count = function(has_ember) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FFZ.prototype._following_get_me = function(tries) {
|
||||||
|
// get_user doesn't properly return an oauth token any longer, so we need to get me manually.
|
||||||
|
if ( ! window.Twitch )
|
||||||
|
// Wait around till the API shows up.
|
||||||
|
return setTimeout(this._following_get_me.bind(this, tries), Math.floor(2000*Math.random()) + 500);
|
||||||
|
|
||||||
|
var f = this;
|
||||||
|
Twitch.api.get("/api/me").done(function(data) {
|
||||||
|
f.log("Fetched User Data -- " + (data.name || data.login));
|
||||||
|
f.__user = data;
|
||||||
|
f._update_following_count();
|
||||||
|
|
||||||
|
}).fail(function() {
|
||||||
|
tries = (tries||0) + 1;
|
||||||
|
if ( tries < 5 )
|
||||||
|
return setTimeout(f._following_get_me.bind(f, tries), Math.floor(2000*Math.random()) + 500);
|
||||||
|
f.log("Failed to get proper user object.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
FFZ.prototype._schedule_following_count = function() {
|
FFZ.prototype._schedule_following_count = function() {
|
||||||
if ( ! this.settings.following_count ) {
|
if ( ! this.settings.following_count ) {
|
||||||
if ( this._following_count_timer ) {
|
if ( this._following_count_timer ) {
|
||||||
|
@ -111,8 +132,13 @@ FFZ.prototype._update_following_count = function() {
|
||||||
|
|
||||||
if ( Live )
|
if ( Live )
|
||||||
Live.load();
|
Live.load();
|
||||||
else
|
else {
|
||||||
Twitch.api && Twitch.api.get("streams/followed", {limit:5, offset:0}, {version:3})
|
var a = {},
|
||||||
|
u = this.get_user();
|
||||||
|
|
||||||
|
a.Authorization = "OAuth " + u.chat_oauth_token;
|
||||||
|
|
||||||
|
Twitch.api && Twitch.api.get("streams/followed", {limit:20, offset:0}, {version:3, headers: a})
|
||||||
.done(function(data) {
|
.done(function(data) {
|
||||||
f._draw_following_count(data._total);
|
f._draw_following_count(data._total);
|
||||||
f._draw_following_channels(data.streams, data._total);
|
f._draw_following_channels(data.streams, data._total);
|
||||||
|
@ -120,6 +146,7 @@ FFZ.prototype._update_following_count = function() {
|
||||||
f._draw_following_count();
|
f._draw_following_count();
|
||||||
f._draw_following_channels();
|
f._draw_following_channels();
|
||||||
})
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,6 @@ var FFZ = window.FrankerFaceZ,
|
||||||
constants = require('../constants'),
|
constants = require('../constants'),
|
||||||
utils = require('../utils'),
|
utils = require('../utils'),
|
||||||
|
|
||||||
TWITCH_BASE = "http://static-cdn.jtvnw.net/emoticons/v1/",
|
|
||||||
|
|
||||||
fix_menu_position = function(container) {
|
fix_menu_position = function(container) {
|
||||||
var swapped = document.body.classList.contains('ffz-sidebar-swap') && ! document.body.classList.contains('ffz-portrait');
|
var swapped = document.body.classList.contains('ffz-sidebar-swap') && ! document.body.classList.contains('ffz-portrait');
|
||||||
|
|
||||||
|
@ -63,7 +61,8 @@ FFZ.prototype.setup_menu = function() {
|
||||||
|
|
||||||
this.log("Hooking the Ember Chat Settings view.");
|
this.log("Hooking the Ember Chat Settings view.");
|
||||||
|
|
||||||
var Settings = window.App && App.__container__.resolve('view:settings');
|
var Settings = window.App && App.__container__.resolve('view:settings'),
|
||||||
|
Layout = App.__container__.lookup('controller:layout');
|
||||||
|
|
||||||
if ( ! Settings )
|
if ( ! Settings )
|
||||||
return;
|
return;
|
||||||
|
@ -155,6 +154,12 @@ FFZ.prototype.setup_menu = function() {
|
||||||
|
|
||||||
menu.appendChild(header);
|
menu.appendChild(header);
|
||||||
menu.appendChild(content);
|
menu.appendChild(content);
|
||||||
|
|
||||||
|
// Maximum Height
|
||||||
|
var e = el.querySelector('.chat-settings');
|
||||||
|
if ( Layout && e )
|
||||||
|
e.style.maxHeight = (Layout.get('windowHeight') - 90) + 'px';
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
ffzTeardown: function() {
|
ffzTeardown: function() {
|
||||||
|
@ -162,6 +167,15 @@ FFZ.prototype.setup_menu = function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Maximum height~!
|
||||||
|
if ( Layout )
|
||||||
|
Layout.addObserver('windowHeight', function() {
|
||||||
|
var el = document.querySelector('.ember-chat .chat-settings');
|
||||||
|
if ( el )
|
||||||
|
el.style.maxHeight = (Layout.get('windowHeight') - 90) + 'px';
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// For some reason, this doesn't work unless we create an instance of the
|
// For some reason, this doesn't work unless we create an instance of the
|
||||||
// chat settings view and then destroy it immediately.
|
// chat settings view and then destroy it immediately.
|
||||||
try {
|
try {
|
||||||
|
@ -225,7 +239,7 @@ FFZ.prototype.build_ui_popup = function(view) {
|
||||||
container.classList.toggle('dark', dark);
|
container.classList.toggle('dark', dark);
|
||||||
|
|
||||||
// Stuff
|
// Stuff
|
||||||
jQuery(inner).find('.html-tooltip').tipsy({live: true, html: true, gravity: jQuery.fn.tipsy.autoNS});
|
jQuery(inner).find('.html-tooltip').tipsy({live: true, html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 's')});
|
||||||
|
|
||||||
|
|
||||||
// Menu Container
|
// Menu Container
|
||||||
|
@ -316,7 +330,7 @@ FFZ.prototype.build_ui_popup = function(view) {
|
||||||
link.title = page.name;
|
link.title = page.name;
|
||||||
link.innerHTML = page.icon;
|
link.innerHTML = page.icon;
|
||||||
|
|
||||||
jQuery(link).tipsy();
|
jQuery(link).tipsy({gravity: utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
|
||||||
|
|
||||||
link.addEventListener("click", this._ui_change_page.bind(this, view, inner, menu, sub_container, key));
|
link.addEventListener("click", this._ui_change_page.bind(this, view, inner, menu, sub_container, key));
|
||||||
|
|
||||||
|
@ -438,11 +452,11 @@ FFZ.menu_pages.channel = {
|
||||||
|
|
||||||
var s = document.createElement('span'),
|
var s = document.createElement('span'),
|
||||||
can_use = is_subscribed || !emote.subscriber_only,
|
can_use = is_subscribed || !emote.subscriber_only,
|
||||||
img_set = 'image-set(url("' + TWITCH_BASE + emote.id + '/1.0") 1x, url("' + TWITCH_BASE + emote.id + '/2.0") 2x, url("' + TWITCH_BASE + emote.id + '/3.0") 4x)';
|
img_set = 'image-set(url("' + constants.TWITCH_BASE + emote.id + '/1.0") 1x, url("' + constants.TWITCH_BASE + emote.id + '/2.0") 2x), url("' + constants.TWITCH_BASE + emote.id + '/3.0") 4x)';
|
||||||
|
|
||||||
s.className = 'emoticon tooltip' + (!can_use ? " locked" : "");
|
s.className = 'emoticon html-tooltip' + (!can_use ? " locked" : "");
|
||||||
|
|
||||||
s.style.backgroundImage = 'url("' + TWITCH_BASE + emote.id + '/1.0")';
|
s.style.backgroundImage = 'url("' + constants.TWITCH_BASE + emote.id + '/1.0")';
|
||||||
s.style.backgroundImage = '-webkit-' + img_set;
|
s.style.backgroundImage = '-webkit-' + img_set;
|
||||||
s.style.backgroundImage = '-moz-' + img_set;
|
s.style.backgroundImage = '-moz-' + img_set;
|
||||||
s.style.backgroundImage = '-ms-' + img_set;
|
s.style.backgroundImage = '-ms-' + img_set;
|
||||||
|
@ -450,7 +464,7 @@ FFZ.menu_pages.channel = {
|
||||||
|
|
||||||
s.style.width = emote.width + "px";
|
s.style.width = emote.width + "px";
|
||||||
s.style.height = emote.height + "px";
|
s.style.height = emote.height + "px";
|
||||||
s.title = emote.regex;
|
s.title = (this.settings.emote_image_hover ? '<img class="emoticon ffz-image-hover" src="' + constants.TWITCH_BASE + emote.id + '/3.0?_=preview">' : '') + emote.regex;
|
||||||
|
|
||||||
s.addEventListener('click', function(can_use, id, code, e) {
|
s.addEventListener('click', function(can_use, id, code, e) {
|
||||||
if ( (e.shiftKey || e.shiftLeft) && f.settings.clickable_emoticons )
|
if ( (e.shiftKey || e.shiftLeft) && f.settings.clickable_emoticons )
|
||||||
|
|
|
@ -2,7 +2,6 @@ var FFZ = window.FrankerFaceZ,
|
||||||
constants = require("../constants"),
|
constants = require("../constants"),
|
||||||
utils = require("../utils"),
|
utils = require("../utils"),
|
||||||
|
|
||||||
TWITCH_BASE = "http://static-cdn.jtvnw.net/emoticons/v1/",
|
|
||||||
BANNED_SETS = {"00000turbo":true};
|
BANNED_SETS = {"00000turbo":true};
|
||||||
|
|
||||||
|
|
||||||
|
@ -166,11 +165,14 @@ FFZ.menu_pages.myemotes = {
|
||||||
if ( (settings === 1 && ! emoji.tw) || (settings === 2 && ! emoji.noto) )
|
if ( (settings === 1 && ! emoji.tw) || (settings === 2 && ! emoji.noto) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
em.className = 'emoticon html-tooltip';
|
var src = settings === 2 ? emoji.noto_src : emoji.tw_src,
|
||||||
em.title = 'Emoji: ' + emoji.raw + '\nName: ' + emoji.name + (emoji.short_name ? '\nShort Name: :' + emoji.short_name + ':' : '');
|
image = this.settings.emote_image_hover ? '<img class="emoticon ffz-image-hover" src="' + src + '">' : '';
|
||||||
|
|
||||||
|
em.className = 'emoticon emoji html-tooltip';
|
||||||
|
em.title = image + 'Emoji: ' + emoji.raw + '<br>Name: ' + emoji.name + (emoji.short_name ? '<br>Short Name: :' + emoji.short_name + ':' : '');
|
||||||
em.addEventListener('click', this._add_emote.bind(this, view, emoji.raw));
|
em.addEventListener('click', this._add_emote.bind(this, view, emoji.raw));
|
||||||
|
|
||||||
em.style.backgroundImage = 'url("' + (settings === 2 ? emoji.noto_src : emoji.tw_src) + '")';
|
em.style.backgroundImage = 'url("' + src + '")';
|
||||||
em.style.backgroundSize = "18px";
|
em.style.backgroundSize = "18px";
|
||||||
|
|
||||||
menu.appendChild(em);
|
menu.appendChild(em);
|
||||||
|
@ -237,21 +239,21 @@ FFZ.menu_pages.myemotes = {
|
||||||
code = constants.KNOWN_CODES[emote.code] || emote.code,
|
code = constants.KNOWN_CODES[emote.code] || emote.code,
|
||||||
|
|
||||||
em = document.createElement('span'),
|
em = document.createElement('span'),
|
||||||
img_set = 'image-set(url("' + TWITCH_BASE + emote.id + '/1.0") 1x, url("' + TWITCH_BASE + emote.id + '/2.0") 2x, url("' + TWITCH_BASE + emote.id + '/3.0") 4x)';
|
img_set = 'image-set(url("' + constants.TWITCH_BASE + emote.id + '/1.0") 1x, url("' + constants.TWITCH_BASE + emote.id + '/2.0") 2x, url("' + constants.TWITCH_BASE + emote.id + '/3.0") 4x)';
|
||||||
|
|
||||||
em.className = 'emoticon html-tooltip';
|
em.className = 'emoticon html-tooltip';
|
||||||
|
|
||||||
if ( this.settings.replace_bad_emotes && constants.EMOTE_REPLACEMENTS[emote.id] ) {
|
if ( this.settings.replace_bad_emotes && constants.EMOTE_REPLACEMENTS[emote.id] ) {
|
||||||
em.style.backgroundImage = 'url("' + constants.EMOTE_REPLACEMENT_BASE + constants.EMOTE_REPLACEMENTS[emote.id] + '")';
|
em.style.backgroundImage = 'url("' + constants.EMOTE_REPLACEMENT_BASE + constants.EMOTE_REPLACEMENTS[emote.id] + '")';
|
||||||
} else {
|
} else {
|
||||||
em.style.backgroundImage = 'url("' + TWITCH_BASE + emote.id + '/1.0")';
|
em.style.backgroundImage = 'url("' + constants.TWITCH_BASE + emote.id + '/1.0")';
|
||||||
em.style.backgroundImage = '-webkit-' + img_set;
|
em.style.backgroundImage = '-webkit-' + img_set;
|
||||||
em.style.backgroundImage = '-moz-' + img_set;
|
em.style.backgroundImage = '-moz-' + img_set;
|
||||||
em.style.backgroundImage = '-ms-' + img_set;
|
em.style.backgroundImage = '-ms-' + img_set;
|
||||||
em.style.backgroudnImage = img_set;
|
em.style.backgroudnImage = img_set;
|
||||||
}
|
}
|
||||||
|
|
||||||
em.title = code;
|
em.title = (this.settings.emote_image_hover ? '<img class="emoticon ffz-image-hover" src="' + constants.TWITCH_BASE + emote.id + '/3.0?_=preview">' : '') + code;
|
||||||
em.addEventListener("click", function(id, c, e) {
|
em.addEventListener("click", function(id, c, e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if ( (e.shiftKey || e.shiftLeft) && f.settings.clickable_emoticons )
|
if ( (e.shiftKey || e.shiftLeft) && f.settings.clickable_emoticons )
|
||||||
|
|
|
@ -84,7 +84,7 @@ FFZ.prototype._update_subscribers = function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
cont.appendChild(stat);
|
cont.appendChild(stat);
|
||||||
jQuery(stat).tipsy(f.is_dashboard ? {"gravity":"s"} : undefined);
|
jQuery(stat).tipsy({gravity: f.is_dashboard ? "s" : utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
|
||||||
}
|
}
|
||||||
|
|
||||||
el.innerHTML = sub_count;
|
el.innerHTML = sub_count;
|
||||||
|
|
38
src/ui/tooltips.js
Normal file
38
src/ui/tooltips.js
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
var FFZ = window.FrankerFaceZ,
|
||||||
|
utils = require('../utils'),
|
||||||
|
constants = require('../constants');
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------
|
||||||
|
// Initialization
|
||||||
|
// ---------------------
|
||||||
|
|
||||||
|
FFZ.prototype.fix_tooltips = function() {
|
||||||
|
// First, override the tooltip mixin.
|
||||||
|
var TipsyTooltip = window.App && App.__container__.resolve('component:tipsy-tooltip');
|
||||||
|
if ( TipsyTooltip ) {
|
||||||
|
this.log("Modifying Tipsy-Tooltip component to use gravity.");
|
||||||
|
TipsyTooltip.reopen({
|
||||||
|
didInsertElement: function() {
|
||||||
|
var gravity = this.get("gravity");
|
||||||
|
if ( ! gravity || typeof gravity === "string" )
|
||||||
|
gravity = utils.tooltip_placement(constants.TOOLTIP_DISTANCE, gravity || 's');
|
||||||
|
|
||||||
|
this.$().tipsy({
|
||||||
|
gravity: gravity
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate all existing tipsy stuff~!
|
||||||
|
this.log('Fixing already existing tooltips.');
|
||||||
|
if ( ! window.jQuery || ! jQuery.cache )
|
||||||
|
return;
|
||||||
|
|
||||||
|
for(var obj_id in jQuery.cache) {
|
||||||
|
var obj = jQuery.cache[obj_id];
|
||||||
|
if ( obj && obj.data && obj.data.tipsy && obj.data.tipsy.options && typeof obj.data.tipsy.options.gravity !== "function" )
|
||||||
|
obj.data.tipsy.options.gravity = utils.tooltip_placement(constants.TOOLTIP_DISTANCE, obj.data.tipsy.options.gravity || 's');
|
||||||
|
}
|
||||||
|
}
|
|
@ -66,6 +66,6 @@ FFZ.ws_commands.viewers = function(data) {
|
||||||
view_count.innerHTML = content;
|
view_count.innerHTML = content;
|
||||||
|
|
||||||
parent.appendChild(view_count);
|
parent.appendChild(view_count);
|
||||||
jQuery(view_count).tipsy(this.is_dashboard ? {"gravity":"s"} : undefined);
|
jQuery(view_count).tipsy({gravity: this.is_dashboard ? "s" : utils.tooltip_placement(constants.TOOLTIP_DISTANCE, 'n')});
|
||||||
}
|
}
|
||||||
}
|
}
|
107
src/utils.js
107
src/utils.js
|
@ -182,10 +182,98 @@ var sanitize_el = document.createElement('span'),
|
||||||
out = es[variant] = r.join("-");
|
out = es[variant] = r.join("-");
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Twitch Emote Tooltips
|
||||||
|
|
||||||
|
SRCSETS = {},
|
||||||
|
build_srcset = function(id) {
|
||||||
|
if ( SRCSETS[id] )
|
||||||
|
return SRCSETS[id];
|
||||||
|
var out = SRCSETS[id] = constants.TWITCH_BASE + id + "/1.0 1x, " + constants.TWITCH_BASE + id + "/2.0 2x, " + constants.TWITCH_BASE + id + "/3.0 4x";
|
||||||
|
return out;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
data_to_tooltip = function(data) {
|
||||||
|
var emote_set = data.set,
|
||||||
|
set_type = data.set_type,
|
||||||
|
|
||||||
|
f = FFZ.get(),
|
||||||
|
image = '';
|
||||||
|
|
||||||
|
if ( data.id && f.settings.emote_image_hover )
|
||||||
|
image = '<img class="emoticon ffz-image-hover" src="' + constants.TWITCH_BASE + data.id + '/3.0?_=preview">';
|
||||||
|
|
||||||
|
if ( set_type === undefined )
|
||||||
|
set_type = "Channel";
|
||||||
|
|
||||||
|
if ( ! emote_set )
|
||||||
|
return image + data.code;
|
||||||
|
|
||||||
|
else if ( emote_set === "--global--" ) {
|
||||||
|
emote_set = "Twitch Global";
|
||||||
|
set_type = null;
|
||||||
|
|
||||||
|
} else if ( emote_set == "--twitch-turbo--" || emote_set == "turbo" || emote_set == "--turbo-faces--" ) {
|
||||||
|
emote_set = "Twitch Turbo";
|
||||||
|
set_type = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return image + "Emoticon: " + data.code + "<br>" + (set_type ? set_type + ": " : "") + emote_set;
|
||||||
|
},
|
||||||
|
|
||||||
|
build_tooltip = function(id, force_update, code) {
|
||||||
|
var emote_data = this._twitch_emotes[id];
|
||||||
|
|
||||||
|
if ( ! emote_data && code ) {
|
||||||
|
var set_id = this._twitch_emote_to_set[id];
|
||||||
|
if ( set_id ) {
|
||||||
|
emote_data = this._twitch_emotes[id] = {
|
||||||
|
code: code,
|
||||||
|
id: id,
|
||||||
|
set: this._twitch_set_to_channel[set_id],
|
||||||
|
set_id: set_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! emote_data )
|
||||||
|
return "???";
|
||||||
|
|
||||||
|
if ( typeof emote_data == "string" )
|
||||||
|
return emote_data;
|
||||||
|
|
||||||
|
if ( ! force_update && emote_data.tooltip )
|
||||||
|
return emote_data.tooltip;
|
||||||
|
|
||||||
|
return emote_data.tooltip = data_to_tooltip(emote_data);
|
||||||
|
},
|
||||||
|
|
||||||
|
load_emote_data = function(id, code, success, data) {
|
||||||
|
if ( ! success )
|
||||||
|
return code;
|
||||||
|
|
||||||
|
if ( code )
|
||||||
|
data.code = code;
|
||||||
|
|
||||||
|
this._twitch_emotes[id] = data;
|
||||||
|
var tooltip = build_tooltip.bind(this)(id);
|
||||||
|
|
||||||
|
var images = document.querySelectorAll('img[data-emote="' + id + '"]');
|
||||||
|
for(var x=0; x < images.length; x++)
|
||||||
|
images[x].title = tooltip;
|
||||||
|
|
||||||
|
return tooltip;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
build_srcset: build_srcset,
|
||||||
|
build_tooltip: build_tooltip,
|
||||||
|
load_emote_data: load_emote_data,
|
||||||
|
|
||||||
|
|
||||||
update_css: function(element, id, css) {
|
update_css: function(element, id, css) {
|
||||||
var all = element.innerHTML,
|
var all = element.innerHTML,
|
||||||
start = "/*BEGIN " + id + "*/",
|
start = "/*BEGIN " + id + "*/",
|
||||||
|
@ -207,6 +295,25 @@ module.exports = {
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
tooltip_placement: function(margin, prefer) {
|
||||||
|
return function() {
|
||||||
|
var dir = {ns: prefer[0], ew: (prefer.length > 1 ? prefer[1] : false)},
|
||||||
|
$this = $(this),
|
||||||
|
half_width = $this.width() / 2,
|
||||||
|
half_height = $this.height() / 2,
|
||||||
|
boundTop = $(document).scrollTop() + half_height + (margin*2),
|
||||||
|
boundLeft = $(document).scrollLeft() + half_width + margin;
|
||||||
|
|
||||||
|
if ($this.offset().top < boundTop) dir.ns = 'n';
|
||||||
|
if ($this.offset().left < boundLeft) dir.ew = 'w';
|
||||||
|
if ($(window).width() + $(document).scrollLeft() - ($this.offset().left + half_width) < margin) dir.ew = 'e';
|
||||||
|
if ($(window).height() + $(document).scrollTop() - ($this.offset().top + half_height) < (2*margin)) dir.ns = 's';
|
||||||
|
|
||||||
|
return dir.ns + (dir.ew ? dir.ew : '');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
splitIRCMessage: splitIRCMessage,
|
splitIRCMessage: splitIRCMessage,
|
||||||
parseIRCTags: parseIRCTags,
|
parseIRCTags: parseIRCTags,
|
||||||
|
|
||||||
|
|
44
style.css
44
style.css
|
@ -21,20 +21,20 @@ body > div.tipsy .tipsy-arrow { opacity: 0.8; }
|
||||||
|
|
||||||
.ffz-hide-recent-past-broadcast .recent-past-broadcast,
|
.ffz-hide-recent-past-broadcast .recent-past-broadcast,
|
||||||
.ffz-hide-view-count .stat.twitch-channel-views,
|
.ffz-hide-view-count .stat.twitch-channel-views,
|
||||||
.ffz-minimal-chat-input .emoticon-selector-toggle,
|
.ffz-minimal-chat-input .chat-interface .emoticon-selector-toggle,
|
||||||
.ffz-menu-replace .emoticon-selector-toggle {
|
.ffz-menu-replace .chat-interface .emoticon-selector-toggle {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-toggle + .ffz-ui-toggle svg,
|
body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .chat-interface .emoticon-selector-toggle + .ffz-ui-toggle svg,
|
||||||
body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-toggle + script + .ffz-ui-toggle svg
|
body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .chat-interface .emoticon-selector-toggle + script + .ffz-ui-toggle svg
|
||||||
{
|
{
|
||||||
height: 14px;
|
height: 14px;
|
||||||
width: 18px;
|
width: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-toggle + .ffz-ui-toggle,
|
body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .chat-interface .emoticon-selector-toggle + .ffz-ui-toggle,
|
||||||
body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-toggle + script + .ffz-ui-toggle {
|
body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .chat-interface .emoticon-selector-toggle + script + .ffz-ui-toggle {
|
||||||
height: 14px;
|
height: 14px;
|
||||||
width: 18px;
|
width: 18px;
|
||||||
top: 28px;
|
top: 28px;
|
||||||
|
@ -263,6 +263,11 @@ body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .emoticon-selector-togg
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ffz-theater-stats .app-main.theatre #channel .player-column:focus .archive_info + .stats-and-actions,
|
||||||
|
.ffz-theater-stats .app-main.theatre #channel .player-column:hover .archive_info + .stats-and-actions {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.ffz-theater-stats .app-main.theatre .player-column:focus #hostmode > div.clearfix,
|
.ffz-theater-stats .app-main.theatre .player-column:focus #hostmode > div.clearfix,
|
||||||
.ffz-theater-stats .app-main.theatre .player-column:hover #hostmode > div.clearfix,
|
.ffz-theater-stats .app-main.theatre .player-column:hover #hostmode > div.clearfix,
|
||||||
.ffz-theater-stats .app-main.theatre .player-column:focus .stats-and-actions,
|
.ffz-theater-stats .app-main.theatre .player-column:focus .stats-and-actions,
|
||||||
|
@ -898,8 +903,17 @@ span.ffz-handle:after { left: 8px }
|
||||||
.ffz-ui-popup.dark .ffz-ui-menu-page { background-color: #1e1e1e; }
|
.ffz-ui-popup.dark .ffz-ui-menu-page { background-color: #1e1e1e; }
|
||||||
|
|
||||||
|
|
||||||
|
/* Positioning Fixes */
|
||||||
|
|
||||||
|
body:not(.ffz-bttv) .ember-chat .chat-settings { bottom: 40px; }
|
||||||
|
body:not(.ffz-bttv) .notification-controls .notify-menu { bottom: 25px; }
|
||||||
|
body:not(.ffz-bttv) .dropmenu.share { margin-bottom: 0; }
|
||||||
|
|
||||||
|
|
||||||
/* Menu Scrollbar */
|
/* Menu Scrollbar */
|
||||||
|
|
||||||
|
.ffz-scrollbar::-webkit-scrollbar,
|
||||||
|
.ember-chat .chat-settings::-webkit-scrollbar,
|
||||||
.conversations-list .conversations-list-inner::-webkit-scrollbar,
|
.conversations-list .conversations-list-inner::-webkit-scrollbar,
|
||||||
.conversation-window .conversation-content::-webkit-scrollbar,
|
.conversation-window .conversation-content::-webkit-scrollbar,
|
||||||
.chat-history::-webkit-scrollbar,
|
.chat-history::-webkit-scrollbar,
|
||||||
|
@ -910,6 +924,8 @@ span.ffz-handle:after { left: 8px }
|
||||||
width: 6px;
|
width: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ffz-scrollbar::-webkit-scrollbar-thumb,
|
||||||
|
.ember-chat .chat-settings::-webkit-scrollbar-thumb,
|
||||||
.conversations-list .conversations-list-inner::-webkit-scrollbar-thumb,
|
.conversations-list .conversations-list-inner::-webkit-scrollbar-thumb,
|
||||||
.conversation-window .conversation-content::-webkit-scrollbar-thumb,
|
.conversation-window .conversation-content::-webkit-scrollbar-thumb,
|
||||||
.chat-history::-webkit-scrollbar-thumb,
|
.chat-history::-webkit-scrollbar-thumb,
|
||||||
|
@ -922,10 +938,14 @@ span.ffz-handle:after { left: 8px }
|
||||||
box-shadow: 0 0 1px 1px rgba(255,255,255,0.25);
|
box-shadow: 0 0 1px 1px rgba(255,255,255,0.25);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ffz-dark .ffz-scrollbar::-webkit-scrollbar-thumb,
|
||||||
.ffz-dark .table::-webkit-scrollbar-thumb,
|
.ffz-dark .table::-webkit-scrollbar-thumb,
|
||||||
.ffz-dark .conversation-window .conversation-content::-webkit-scrollbar-thumb,
|
.ffz-dark .conversation-window .conversation-content::-webkit-scrollbar-thumb,
|
||||||
.ffz-dark .conversations-list .conversations-list-inner::-webkit-scrollbar-thumb,
|
.ffz-dark .conversations-list .conversations-list-inner::-webkit-scrollbar-thumb,
|
||||||
|
.ffz-dark .conversation-input-bar .emoticon-selector-box .all-emotes::-webkit-scrollbar-thumb,
|
||||||
|
|
||||||
|
.theatre .ffz-scrollbar::-webkit-scrollbar-thumb,
|
||||||
|
.theatre .ember-chat .chat-settings::-webkit-scrollbar-thumb,
|
||||||
.theatre .conversation-window .conversation-content::-webkit-scrollbar-thumb,
|
.theatre .conversation-window .conversation-content::-webkit-scrollbar-thumb,
|
||||||
.theatre .conversations-list .conversations-list-inner::-webkit-scrollbar-thumb,
|
.theatre .conversations-list .conversations-list-inner::-webkit-scrollbar-thumb,
|
||||||
|
|
||||||
|
@ -934,11 +954,15 @@ span.ffz-handle:after { left: 8px }
|
||||||
.theatre .ffz-ui-menu-page::-webkit-scrollbar-thumb,
|
.theatre .ffz-ui-menu-page::-webkit-scrollbar-thumb,
|
||||||
.theatre .ffz-ui-sub-menu-page::-webkit-scrollbar-thumb
|
.theatre .ffz-ui-sub-menu-page::-webkit-scrollbar-thumb
|
||||||
|
|
||||||
|
.dark .ffz-scrollbar::-webkit-scrollbar-thumb,
|
||||||
|
.dark .ember-chat .chat-settings::-webkit-scrollbar-thumb,
|
||||||
.dark .chat-history::-webkit-scrollbar-thumb,
|
.dark .chat-history::-webkit-scrollbar-thumb,
|
||||||
.dark .emoticon-selector-box .all-emotes::-webkit-scrollbar-thumb,
|
.dark .emoticon-selector-box .all-emotes::-webkit-scrollbar-thumb,
|
||||||
.dark .ffz-ui-menu-page::-webkit-scrollbar-thumb,
|
.dark .ffz-ui-menu-page::-webkit-scrollbar-thumb,
|
||||||
.dark .ffz-ui-sub-menu-page::-webkit-scrollbar-thumb,
|
.dark .ffz-ui-sub-menu-page::-webkit-scrollbar-thumb,
|
||||||
|
|
||||||
|
.force-dark .ffz-scrollbar::-webkit-scrollbar-thumb,
|
||||||
|
.force-dark .ember-chat .chat-settings::-webkit-scrollbar-thumb,
|
||||||
.force-dark .chat-history::-webkit-scrollbar-thumb,
|
.force-dark .chat-history::-webkit-scrollbar-thumb,
|
||||||
.force-dark .emoticon-selector-box .all-emotes::-webkit-scrollbar-thumb,
|
.force-dark .emoticon-selector-box .all-emotes::-webkit-scrollbar-thumb,
|
||||||
.force-dark .ffz-ui-menu-page::-webkit-scrollbar-thumb,
|
.force-dark .ffz-ui-menu-page::-webkit-scrollbar-thumb,
|
||||||
|
@ -954,7 +978,6 @@ img.channel_background[src="null"] { display: none; }
|
||||||
.ffz-moderation-card {
|
.ffz-moderation-card {
|
||||||
border: 2px solid #cbcbcb;
|
border: 2px solid #cbcbcb;
|
||||||
max-width: 340px;
|
max-width: 340px;
|
||||||
/*box-shadow: #808080 0 0 5px;*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.ffz-moderation-card .extra-interface {
|
.ffz-moderation-card .extra-interface {
|
||||||
|
@ -967,6 +990,7 @@ img.channel_background[src="null"] { display: none; }
|
||||||
|
|
||||||
.ffz-moderation-card.ffz-has-info h3.name {
|
.ffz-moderation-card.ffz-has-info h3.name {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ffz-moderation-card .info {
|
.ffz-moderation-card .info {
|
||||||
|
@ -1073,7 +1097,7 @@ img.channel_background[src="null"] { display: none; }
|
||||||
}
|
}
|
||||||
|
|
||||||
.mod-icons .custom {
|
.mod-icons .custom {
|
||||||
text-indent: 0;
|
text-indent: 0 !important;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
|
@ -1106,7 +1130,7 @@ img.channel_background[src="null"] { display: none; }
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.more-messages-indicator {
|
body:not(.ffz-bttv) .more-messages-indicator {
|
||||||
/* This looks better when it's full width. */
|
/* This looks better when it's full width. */
|
||||||
margin: 0 -20px;
|
margin: 0 -20px;
|
||||||
}
|
}
|
||||||
|
@ -2047,6 +2071,8 @@ li[data-name="following"] a {
|
||||||
|
|
||||||
/* Conversations */
|
/* Conversations */
|
||||||
|
|
||||||
|
.conversation-chat-line.action .colon,
|
||||||
|
.conversation-input-bar .emoticon-selector .tabs,
|
||||||
.conversation-preview-line .badges,
|
.conversation-preview-line .badges,
|
||||||
body.ffz-conv-title-clickable .conversation-header span.conversation-header-name,
|
body.ffz-conv-title-clickable .conversation-header span.conversation-header-name,
|
||||||
body:not(.ffz-conv-title-clickable) .conversation-header a.conversation-header-name { display:none }
|
body:not(.ffz-conv-title-clickable) .conversation-header a.conversation-header-name { display:none }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue