1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-06-28 15:27:43 +00:00

3.5.194. Rename controller:layout and controller:login to be services. Rewrite styles to better work with the new chat DOM layout. Stop exposing tokens to the built-in chat templates to avoid rendering errors and improve performance. Schedule scrolling events with requestAnimationFrame. Very initial bits support that doesn't actually do anything yet. Fix SRL race information.

This commit is contained in:
SirStendec 2016-06-02 20:04:40 -04:00
parent 57a95986d3
commit ee21ab28c3
21 changed files with 218 additions and 94 deletions

View file

@ -130,7 +130,7 @@ FFZ.prototype.setup_colors = function() {
this._update_colors();
// Events for rebuilding colors.
var Layout = utils.ember_lookup('controller:layout'),
var Layout = utils.ember_lookup('service:layout'),
Settings = utils.ember_lookup('controller:settings');
if ( Layout )
@ -654,7 +654,7 @@ FFZ.prototype._rebuild_colors = function() {
FFZ.prototype._update_colors = function(darkness_only) {
// Update the lines. ALL of them.
var Layout = utils.ember_lookup('controller:layout'),
var Layout = utils.ember_lookup('service:layout'),
Settings = utils.ember_lookup('controller:settings'),
is_dark = (Layout && Layout.get('isTheatreMode')) || (Settings && Settings.get('settings.darkMode')),

View file

@ -233,7 +233,7 @@ FFZ.prototype._modify_cindex = function(view) {
f.rebuild_race_ui();
if ( f.settings.auto_theater ) {
var Layout = utils.ember_lookup('controller:layout');
var Layout = utils.ember_lookup('service:layout');
if ( Layout )
Layout.set('isTheatreMode', true);
}

View file

@ -134,7 +134,7 @@ FFZ.prototype._modify_conversation_menu = function(component) {
FFZ.prototype._modify_conversation_window = function(component) {
var f = this,
Layout = utils.ember_lookup('controller:layout');
Layout = utils.ember_lookup('service:layout');
component.reopen({
headerBadges: Ember.computed("thread.participants", "currentUsername", function() {
@ -178,7 +178,7 @@ FFZ.prototype._modify_conversation_window = function(component) {
FFZ.prototype._modify_conversation_line = function(component) {
var f = this,
Layout = utils.ember_lookup('controller:layout');
Layout = utils.ember_lookup('service:layout');
component.reopen({
tokenizedMessage: function() {

View file

@ -33,6 +33,59 @@ FFZ.prototype.setup_profile_following = function() {
this._following_cache = {};
this._follower_cache = {};
/*try {
var ChannelSerializer = window.require("web-client/serializers/new-channel"),
BaseSerializer = window.require("web-client/serializers/application"),
process_channel = function(chan) {
var cid = chan.name;
return {
type: "new-channel",
id: cid,
attributes: chan,
relationships: {
following: {
links: {
related: "/kraken/users/" + cid + "/follows/channels?offset=0&on_site=1"
}
}
}
}
};
var ser = ChannelSerializer.default = BaseSerializer.default.extend({
normalizeFindRecordResponse: function(e, t, a, r) {
var l = process_channel(a);
return this._super(e, t, {
data: l
}, r)
},
normalizeResponse: function(e, t, a, r, l) {
if ( ! a.follows )
return this._super.apply(this, arguments);
f.log("Normalizing Response", [e, t, a, r, l]);
var i = this.extractMeta(e, t, a),
o = a.follows.map(function(e) {
return process_channel(e.channel);
}),
d = {
data: o,
meta: i
};
return this._super(e, t, d, r, l);
}
});
App.registry.unregister('serializer:new-channel');
App.registry.register('serializer:new-channel', ser);
} catch(err) {
this.error("Unable to modify the Ember new-channel serializer", err);
}*/
// First, we need to hook the model. This is what we'll use to grab the following notification state,
// rather than making potentially hundreds of API requests.
var Following = utils.ember_resolve('model:kraken-channel-following');

View file

@ -39,7 +39,7 @@ FFZ.settings_info.portrait_mode = {
if ( this.has_bttv )
return;
var Layout = utils.ember_lookup('controller:layout');
var Layout = utils.ember_lookup('service:layout');
if ( ! Layout )
return;
@ -126,7 +126,7 @@ FFZ.settings_info.right_column_width = {
if ( this.has_bttv )
return;
var Layout = utils.ember_lookup('controller:layout');
var Layout = utils.ember_lookup('service:layout');
if ( ! Layout )
return;
@ -151,12 +151,13 @@ FFZ.prototype.setup_layout = function() {
s.id = 'ffz-layout-css';
document.head.appendChild(s);
this.log("Hooking the Ember Layout controller.");
var Layout = utils.ember_lookup('controller:layout'),
var Layout = utils.ember_lookup('service:layout'),
f = this;
if ( ! Layout )
return;
return this.log("Unable to locate the Ember service:layout");
this.log("Hooking the Ember service:layout");
Layout.reopen({
rightColumnWidth: 340,

View file

@ -637,11 +637,15 @@ FFZ.prototype.save_aliases = function() {
FFZ.prototype._modify_chat_line = function(component, is_vod) {
var f = this,
Layout = utils.ember_lookup('controller:layout'),
Layout = utils.ember_lookup('service:layout'),
Settings = utils.ember_lookup('controller:settings');
component.reopen({
tokenizedMessage: function() {
return [];
}.property('msgObject.message'),
ffzTokenizedMessage: function() {
try {
return f.tokenize_chat_line(this.get('msgObject'));
} catch(err) {
@ -650,7 +654,7 @@ FFZ.prototype._modify_chat_line = function(component, is_vod) {
}
}.property("msgObject.message", "isChannelLinksDisabled", "currentUserNick", "msgObject.from", "msgObject.tags.emotes"),
lineChanged: Ember.observer("msgObject.deleted", "isModeratorOrHigher", "msgObject.ffz_old_messages", function() {
lineChanged: Ember.observer("msgObject.deleted", "isModeratorOrHigher", "msgObject.ffz_old_messages", "ffzTokenizedMessage", function() {
this.$(".mod-icons").replaceWith(this.buildModIconsHTML());
if ( this.get("msgObject.deleted") ) {
this.$(".message").replaceWith(this.buildDeletedMessageHTML());
@ -812,7 +816,7 @@ FFZ.prototype._modify_chat_line = function(component, is_vod) {
} else
output = '<span class="message">';
output += f.render_tokens(this.get('tokenizedMessage'), true, is_whisper && f.settings.filter_whispered_links && this.get("ffzUserLevel") < 4);
output += f.render_tokens(this.get('ffzTokenizedMessage'), true, is_whisper && f.settings.filter_whispered_links && this.get("ffzUserLevel") < 4);
var old_messages = this.get('msgObject.ffz_old_messages');
if ( old_messages && old_messages.length )
@ -821,15 +825,10 @@ FFZ.prototype._modify_chat_line = function(component, is_vod) {
return output + '</span>';
},
//tagName: "li",
ffzRender: function() {
var el = this.get('element'),
output = this.buildSenderHTML();
if ( el.tagName === 'DIV' )
return this.rerender();
if ( this.get('msgObject.deleted') )
output += this.buildDeletedMessageHTML()
else
@ -868,7 +867,7 @@ FFZ.prototype._modify_chat_subline = function(component) {
this.set('msgObject._line', null);
},
didUpdate: function() { this.ffzRender(); },
//didUpdate: function() { this.ffzRender(); },
click: function(e) {
if ( ! e.target )
@ -966,6 +965,10 @@ FFZ.prototype._modify_vod_line = function(component) {
attributeBindings: ["msgObject.room:data-room", "msgObject.from:data-sender", "msgObject.deleted:data-deleted"],
tokenizedMessage: function() {
return [];
}.property('msgObject.message'),
ffzTokenizedMessage: function() {
try {
return f.tokenize_vod_line(this.get('msgObject'), !(this.get('enableLinkification') || this.get('isModeratorOrHigher')));
} catch(err) {
@ -992,7 +995,7 @@ FFZ.prototype._modify_vod_line = function(component) {
return '<span clas="deleted">&lt;message deleted&gt;</span>';
},
didUpdate: function() { this.ffzRender() },
//didUpdate: function() { this.ffzRender() },
didInsertElement: function() { this.ffzRender() },
ffzRender: function() {

View file

@ -1172,7 +1172,7 @@ FFZ.prototype._build_mod_card_history = function(msg, modcard, show_from) {
var raw_color = msg.color,
colors = raw_color && this._handle_color(raw_color),
Layout = utils.ember_lookup('controller:layout'),
Layout = utils.ember_lookup('service:layout'),
Settings = utils.ember_lookup('controller:settings'),
is_dark = (Layout && Layout.get('isTheatreMode')) || (Settings && Settings.get('settings.darkMode'));

View file

@ -44,7 +44,7 @@ FFZ.settings_info.classic_player = {
on_update: function(val) {
utils.toggle_cls('ffz-classic-player')(val);
var Layout = utils.ember_lookup('controller:layout');
var Layout = utils.ember_lookup('service:layout');
if ( Layout )
Layout.set('PLAYER_CONTROLS_HEIGHT', val ? 32 : 0);
}
@ -73,7 +73,7 @@ FFZ.prototype.setup_player = function() {
utils.toggle_cls('ffz-player-volume')(this.settings.player_volume_bar);
utils.toggle_cls('ffz-classic-player')(this.settings.classic_player);
var Layout = utils.ember_lookup('controller:layout');
var Layout = utils.ember_lookup('service:layout');
if ( Layout )
Layout.set('PLAYER_CONTROLS_HEIGHT', this.settings.classic_player ? 32 : 0);

View file

@ -371,7 +371,8 @@ FFZ.prototype._modify_rview = function(view) {
s = this._$chatMessagesScroller;
Ember.run.next(function() {
setTimeout(function(){
// Trying random performance tweaks for fun and profit!
(window.requestAnimationFrame||setTimeout)(function(){
if ( e.ffz_frozen || ! s || ! s.length )
return;
@ -1104,7 +1105,7 @@ FFZ.prototype._modify_room = function(room) {
// Now that we've reset the tokens, if there's a line for this,
if ( last_ban._line )
Ember.propertyDidChange(last_ban._line, 'tokenizedMessage');
Ember.propertyDidChange(last_ban._line, 'ffzTokenizedMessage');
}
}
@ -1218,7 +1219,8 @@ FFZ.prototype._modify_room = function(room) {
// We need either the amount of chat delay past the first message, if chat_delay is on, or the
// amount of time from the last batch.
now = now || Date.now();
var delay = Math.max(
var t = this,
delay = Math.max(
(f.settings.chat_delay !== 0 ? 50 + Math.max(0, (f.settings.chat_delay + (this.ffzPending[0].time||0)) - now) : 0),
(f.settings.chat_batching !== 0 ? Math.max(0, f.settings.chat_batching - (now - (this._ffz_last_batch||0))) : 0));
@ -1316,16 +1318,23 @@ FFZ.prototype._modify_room = function(room) {
var room = f.rooms && f.rooms[msg.room];
if ( room ) {
var chat_history = room.user_history = room.user_history || {},
user_history = room.user_history[msg.from] = room.user_history[msg.from] || [];
user_history = room.user_history[msg.from] = room.user_history[msg.from] || [],
last_history = user_history.length && user_history[user_history.length - 1],
user_history.push({
from: msg.from,
tags: {'display-name': msg.tags && msg.tags['display-name']},
message: msg.message,
cachedTokens: msg.cachedTokens,
style: msg.style,
date: msg.date
});
new_msg = {
from: msg.from,
tags: {'display-name': msg.tags && msg.tags['display-name']},
message: msg.message,
cachedTokens: msg.cachedTokens,
style: msg.style,
date: msg.date
};
// Preserve message order if we *just* received a ban.
if ( last_history && last_history.is_delete && (msg.date - last_history.date) <= 200 ) {
user_history.splice(user_history.length - 1, 0, new_msg);
} else
user_history.push(new_msg);
if ( user_history.length > 20 )
user_history.shift();

View file

@ -277,7 +277,7 @@ FFZ.prototype._modify_vod_chat_display = function(component) {
return;
Ember.run.next(function() {
setTimeout(function() {
(window.requestAnimationFrame||setTimeout)(function() {
if ( e.ffz_frozen )
return;

View file

@ -151,7 +151,7 @@ FFZ.prototype.process_rechat_line = function(line, reprocess) {
user_id = line.getAttribute('data-sender'),
room_id = line.getAttribute('data-room'),
Layout = utils.ember_lookup('controller:layout'),
Layout = utils.ember_lookup('service:layout'),
Settings = utils.ember_lookup('controller:settings'),
is_dark = (Layout && Layout.get('isTheatreMode')) || (Settings && Settings.get('settings.darkMode')),

View file

@ -37,7 +37,7 @@ FFZ.msg_commands = {};
// Version
var VER = FFZ.version_info = {
major: 3, minor: 5, revision: 190,
major: 3, minor: 5, revision: 194,
toString: function() {
return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || "");
}
@ -116,7 +116,7 @@ FFZ.prototype.get_user = function(force_reload) {
if ( ! force_reload && this.__user )
return this.__user;
var LC = FFZ.utils.ember_lookup('controller:login'),
var LC = FFZ.utils.ember_lookup('service:login'),
user = LC ? LC.get('userData') : undefined;
if ( ! user && window.PP && PP.login )
@ -225,10 +225,11 @@ FFZ.prototype.initialize = function(increment, delay) {
// Twitch ember application is ready.
// Pages we don't want to interact with at all.
if ( location.hostname === 'passport.twitch.tv' || /^\/user\/two_factor/.test(location.pathname) ) {
this.log("Found authentication sub-page. Not initializing.");
return;
}
if ( location.hostname === 'passport.twitch.tv' || /^\/user\/two_factor/.test(location.pathname) )
return this.log("Found authentication sub-page. Not initializing.");
if ( ['im.twitch.tv', 'api.twitch.tv'].indexOf(location.hostname) !== -1 )
return this.log("Found banned sub-domain. Not initializing.");
// Check for the player
if ( location.hostname === 'player.twitch.tv' ) {

View file

@ -1,6 +1,5 @@
/* Regular Alternating Background */
.conversation-chat-lines > div:nth-child(2n+0):before,
.chat-lines > div:nth-child(2n+0) > .chat-line:before,
.chat-line:nth-child(2n+0):before {
background-color: rgba(0,0,0, 0.1);
}
@ -12,10 +11,6 @@
.theatre .conversation-chat-lines > div:nth-child(2n+0):before,
.theatre .chat-line:nth-child(2n+0):before,
.theatre .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,
.dark .chat-line:nth-child(2n+0):before,
.force-dark .chat-line:nth-child(2n+0):before {
@ -29,7 +24,6 @@
}
.chat-lines > div:nth-child(2n+0) > .chat-line.whisper:nth-child(2n+0):before,
.chat-line.whisper:nth-child(2n+0):before {
background-color: rgba(185, 163, 227, 0.4);
}
@ -40,10 +34,6 @@
background-color: rgba(100, 65, 165, 0.2);
}
.theatre .chat-lines > div:nth-child(2n+0) > .chat-line.whisper:before,
.dark .chat-lines > div:nth-child(2n+0) > .chat-line.whisper:before,
.force-dark .chat-lines > div:nth-child(2n+0) > .chat-line.whisper:before,
.theatre .chat-line.whisper:nth-child(2n+0):before,
.dark .chat-line.whisper:nth-child(2n+0):before,
.force-dark .chat-line.whisper:nth-child(2n+0):before {

View file

@ -17,14 +17,12 @@
/* Hide First Line */
.conversation-chat-lines > div:first-child:before,
.chat-lines > div:first-of-type > .chat-line:before,
.chatReplay .chat-line:first-of-type:before {
.chat-line:first-of-type:before {
border-top-color: transparent !important;
}
/* Hide Last Line */
.conversation-chat-lines > div:last-child:nth-child(odd):before,
.chat-lines > div:last-of-type:nth-child(odd) > .chat-line:before,
.chatReplay .chat-line:last-of-type:nth-child(odd):before {
.chat-line:last-of-type:nth-child(odd):before {
border-bottom-color: transparent !important;
}

View file

@ -476,7 +476,7 @@ FFZ.prototype.tokenize_vod_line = function(msgObject, delete_links) {
}
FFZ.prototype.tokenize_chat_line = function(msgObject, prevent_notification, delete_links) {
FFZ.prototype.tokenize_chat_line = function(msgObject, prevent_notification, delete_links, use_bits) {
if ( msgObject.cachedTokens )
return msgObject.cachedTokens;
@ -489,6 +489,9 @@ FFZ.prototype.tokenize_chat_line = function(msgObject, prevent_notification, del
tokens = [msg];
// Standard tokenization
if ( use_bits && helpers && helpers.tokenizeBits )
tokens = helpers.tokenizeBits(tokens);
if ( helpers && helpers.linkifyMessage ) {
var labels = msgObject.labels || [],
mod_or_higher = labels.indexOf("owner") !== -1 ||

View file

@ -52,7 +52,7 @@ FFZ.ws_commands.update_news = function(version) {
// About Page
// -------------------
var include_html = function(heading_text, filename) {
var include_html = function(heading_text, filename, callback) {
return function(view, container) {
var heading = createElement('div', 'chat-menu-content center');
heading.innerHTML = '<h1>FrankerFaceZ</h1>' + (heading_text ? '<div class="ffz-about-subheading">' + heading_text + '</div>' : '');
@ -67,6 +67,8 @@ var include_html = function(heading_text, filename) {
jQuery('#ffz-old-news', container).css('display', 'block');
});
typeof callback === "function" && callback(view, container);
}).fail(function(data) {
var content = createElement('div', 'chat-menu-content menu-side-padding');
content.textContent = 'There was an error loading this page from the server.';
@ -252,7 +254,7 @@ FFZ.menu_pages.about = {
},
changelog: {
name: "Changelog",
name: "Changes",
wide: true,
render: include_html("change log", constants.SERVER + "script/changelog.html")
},
@ -272,11 +274,19 @@ FFZ.menu_pages.about = {
},*/
credits: {
name: "Credits",
name: "Credit",
wide: true,
render: include_html("credits", constants.SERVER + "script/credits.html")
},
/*status: {
name: "Status",
wide: true,
render: include_html("server status", constants.SERVER + "script/status.html", function(view, container) {
})
},*/
debugging: {
name: "Debug",
wide: true,

View file

@ -77,7 +77,7 @@ FFZ.ffz_commands.following = function(room, args) {
FFZ.ws_on_close.push(function() {
var controller = utils.ember_lookup('controller:channel'),
current_id = controller && controller.get('id'),
current_id = controller && controller.get('content.id'),
current_host = controller && controller.get('hostModeTarget.id'),
need_update = false;

View file

@ -46,7 +46,7 @@ FFZ.prototype.setup_menu = function() {
this.log("Hooking the Ember Chat Settings view.");
var Settings = utils.ember_resolve('view:settings'),
Layout = utils.ember_lookup('controller:layout'),
Layout = utils.ember_lookup('service:layout'),
f = this;
if ( ! Settings )

View file

@ -36,7 +36,7 @@ FFZ.settings_info.srl_races = {
FFZ.ws_on_close.push(function() {
var controller = utils.ember_lookup('controller:channel'),
current_id = controller && controller.get('id'),
current_id = controller && controller.get('content.id'),
current_host = controller && controller.get('hostModeTarget.id'),
need_update = false;
@ -56,7 +56,7 @@ FFZ.ws_on_close.push(function() {
FFZ.ws_commands.srl_race = function(data) {
var controller = utils.ember_lookup('controller:channel'),
current_id = controller && controller.get('id'),
current_id = controller && controller.get('content.id'),
current_host = controller && controller.get('hostModeTarget.id'),
need_update = false;
@ -92,7 +92,7 @@ FFZ.ws_commands.srl_race = function(data) {
FFZ.prototype.rebuild_race_ui = function() {
var controller = utils.ember_lookup('controller:channel'),
channel_id = controller && controller.get('id'),
channel_id = controller && controller.get('content.id'),
hosted_id = controller && controller.get('hostModeTarget.id');
if ( ! this._cindex )
@ -111,7 +111,7 @@ FFZ.prototype.rebuild_race_ui = function() {
} else {
if ( ! race_container ) {
race_container = document.createElement('span');
race_container = utils.createElement('span', 'balloon-wrapper inline');
race_container.id = 'ffz-ui-race';
race_container.setAttribute('data-channel', channel_id);
@ -143,7 +143,7 @@ FFZ.prototype.rebuild_race_ui = function() {
} else {
if ( ! race_container ) {
race_container = document.createElement('span');
race_container = utils.createElement('span', 'balloon-wrapper inline');
race_container.id = 'ffz-ui-race';
race_container.setAttribute('data-channel', hosted_id);
@ -191,10 +191,10 @@ FFZ.prototype._build_race_popup = function(container, channel_id) {
pos = el.offsetLeft + el.offsetWidth,
race = this.srl_races[channel_id];
var popup = document.createElement('div'), out = '';
var popup = utils.createElement('div', 'share balloon balloon--md balloon--up balloon--dropmenu'), out = '';
popup.id = 'ffz-race-popup';
popup.setAttribute('data-channel', channel_id);
popup.className = (pos >= 300 ? 'right' : 'left') + ' share dropmenu';
//popup.className = (pos >= 300 ? 'right' : 'left') + ' share dropmenu';
this._popup_kill = this._race_kill.bind(this);
this._popup_allow_parent = true;
@ -212,13 +212,12 @@ FFZ.prototype._build_race_popup = function(container, channel_id) {
var height = document.querySelector('.app-main.theatre') ? document.body.clientHeight - 300 : container.parentElement.offsetTop - 175,
controller = utils.ember_lookup('controller:channel'),
display_name = controller ? controller.get('display_name') : FFZ.get_capitalization(channel_id),
display_name = controller && controller.get('content.id') === channel_id ? controller.get('content.display_name') : FFZ.get_capitalization(channel_id),
tweet = encodeURIComponent("I'm watching " + display_name + " race " + race.goal + " in " + race.game + " on SpeedRunsLive!");
out = '<div class="heading"><div></div><span></span></div>';
out = '<div class="heading"><div></div><span class="html-tooltip"></span></div>';
out += '<div class="table" style="max-height:' + height + 'px"><table><thead><tr><th>#</th><th>Entrant</th><th>&nbsp;</th><th>Time</th></tr></thead>';
out += '<tbody></tbody></table></div>';
out += '<div class="divider"></div>';
out += '<iframe class="twitter_share_button" style="width:130px; height:25px" src="https://platform.twitter.com/widgets/tweet_button.html?text=' + tweet + '%20Watch%20at&via=Twitch&url=http://www.twitch.tv/' + channel_id + '"></iframe>';
@ -266,7 +265,7 @@ FFZ.prototype._update_race = function(container, not_timer) {
if ( popup ) {
var tbody = popup.querySelector('tbody'),
timer = popup.querySelector('.heading span'),
timer = popup.querySelector('.heading > span'),
info = popup.querySelector('.heading div');
tbody.innerHTML = '';
@ -310,7 +309,7 @@ FFZ.prototype._update_race = function(container, not_timer) {
place = utils.place_string(ent.place),
comment = ent.comment ? utils.sanitize(ent.comment) : "";
tbody.innerHTML += '<tr' + (comment ? ' title="' + comment + '"' : '') + ' class="' + ent.state + '"><td>' + place + '</td><td>' + name + '</td><td>' + twitch_link + hitbox_link + '</td><td class="time">' + (ent.state == "forfeit" ? "Forfeit" : time) + '</td></tr>';
tbody.innerHTML += '<tr' + (comment ? ' title="' + comment + '"' : '') + ' class="' + ent.state + (comment ? ' tooltip' : '') + '"><td>' + place + '</td><td>' + name + '</td><td>' + twitch_link + hitbox_link + '</td><td class="time">' + (ent.state == "forfeit" ? "Forfeit" : time) + '</td></tr>';
}
if ( this._race_game != race.game || this._race_goal != race.goal ) {
@ -318,9 +317,18 @@ FFZ.prototype._update_race = function(container, not_timer) {
this._race_goal = race.goal;
var game = utils.sanitize(race.game),
goal = utils.sanitize(race.goal);
goal = utils.unquote_attr(race.goal),
old_goal = popup.getAttribute('data-old-goal');
info.innerHTML = '<h2 title="' + game + '">' + game + "</h2><b>Goal: </b>" + goal;
if ( goal !== old_goal ) {
popup.setAttribute('data-old-goal', goal);
goal = goal ? this.render_tokens(this.tokenize_line("jtv", null, goal, true)) : '';
info.innerHTML = '<h2 class="tooltip" title="' + game + '">' + game + '</h2><span class="goal"><b>Goal: </b>' + goal + '</span>';
}
}
if ( race.time ) {
timer.title = 'Started at: <nobr>' + utils.sanitize(utils.parse_date(1000 * race.time).toLocaleString()) + '</nobr>';
}
if ( ! elapsed )

View file

@ -9,6 +9,10 @@ var sanitize_el = document.createElement('span'),
return sanitize_el.innerHTML;
},
unquote_attr = function(msg) {
return msg.replace(/&amp;/g, '&').replace(/&quot;/g, '"').replace(/&apos;/g, "'").replace(/&gt;/g, '>').replace(/&lt;/g, '<');
},
escape_regex = RegExp.escape || function(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
},
@ -388,6 +392,7 @@ module.exports = FFZ.utils = {
},
sanitize: sanitize,
unquote_attr: unquote_attr,
quote_attr: quote_attr,
date_string: function(date) {

View file

@ -54,12 +54,12 @@ body:not(.ffz-minimal-chat-input):not(.ffz-menu-replace) .chat-interface .emotic
.ember-chat-container.dark .ffz-ui-toggle svg.svg-emoticons path,
.chat-container.dark .ffz-ui-toggle svg.svg-emoticons path,
.app-main.theatre .ffz-ui-toggle svg.svg-emoticons path,
body.ffz-bttv-dark .ffz-ui-toggle svg.svg-emoticons path { fill: #888; }
body.ffz-bttv-dark .ffz-ui-toggle svg.svg-emoticons path { fill: #555; }
.ember-chat-container.dark .ffz-ui-toggle:hover svg.svg-emoticons path,
.chat-container.dark .ffz-ui-toggle:hover svg.svg-emoticons path,
.app-main.theatre .ffz-ui-toggle:hover svg.svg-emoticons path,
body.ffz-bttv-dark .ffz-ui-toggle:hover svg.svg-emoticons path { fill: #777; }
body.ffz-bttv-dark .ffz-ui-toggle:hover svg.svg-emoticons path { fill: #999; }
.ffz-ui-toggle.no-emotes svg.svg-emoticons path { fill: rgba(80,0,0,0.2); }
@ -360,50 +360,79 @@ body.ffz-bttv-dark .ffz-ui-toggle.blue.live:hover svg.svg-emoticons path { fill:
#ffz-race-popup {
position: absolute;
bottom: 0;
display: block;
background-image: url("//cdn.frankerfacez.com/script/zreknarf-bg.png");
background-repeat: no-repeat;
padding: 1rem;
background-position: 115% 110%;
}
#ffz-race-popup.right { right: 10px; }
#ffz-race-popup .heading {
margin: -20px -20px 20px;
width: 340px; height: 65px;
margin: -1rem -1rem 1rem;
height: 65px;
position: relative;
}
#ffz-race-popup .heading div {
padding: 10px 0 0 20px;
max-width: 240px;
padding: 0 1rem;
}
#ffz-race-popup .heading h2,
#ffz-race-popup .heading .goal {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
#ffz-race-popup .heading .goal {
display: block;
margin: calc(-1rem + 1px);
padding: calc(1rem - 1px);
}
#ffz-race-popup .heading .goal:hover {
white-space: normal;
background-color: rgba(255,255,255,0.9);
border-bottom: 1px solid rgba(0,0,0,0.2);
}
.theatre #ffz-race-popup .heading .goal:hover,
.ffz-dark #ffz-race-popup .heading .goal:hover {
background-color: rgba(16,16,16,0.9);
border-color: rgba(255,255,255,0.2);
}
#ffz-race-popup .heading h2 {
max-width: 240px;
font-size: 1.5em;
padding-bottom: 5px;
display: block;
width: 240px;
max-height: 45px;
overflow: hidden;
text-overflow: ellipsis;
width: 200px;
margin-bottom: 0;
}
#ffz-race-popup .heading span {
#ffz-race-popup .heading > span {
line-height: 30px;
position: absolute;
top: 17.5px;
right: 20px;
top: 7.5px;
right: 1rem;
padding: 0 5px;
background: rgba(0,0,0,0.5);
color: #fff;
border-radius: 5px;
}
#ffz-race-popup .right { text-align: right; }
#ffz-race-popup .right {
padding-top: 0;
text-align: right;
}
#ffz-race-popup .table {
overflow-y: auto;
border-bottom: 1px solid;
margin-bottom: 1rem;
}
#ffz-race-popup table {
@ -587,6 +616,16 @@ body.ffz-bttv-dark .ffz-ui-toggle.blue.live:hover svg.svg-emoticons path { fill:
.list-header span.right { float: right; }
.ember-chat .chat-menu .list-header.sub-header {
border-top: none;
margin: 0 20px;
padding: 5px 0 0;
}
.ember-chat .chat-menu .list-header.sub-header + .chat-menu-content {
padding-top: 0;
}
.chat-menu-content.collapsable .heading span.right {
padding-right: 15px;
}
@ -635,6 +674,10 @@ body.ffz-bttv-dark .ffz-ui-toggle.blue.live:hover svg.svg-emoticons path { fill:
border-bottom: 1px dotted rgba(127,127,127,0.5);
}
.ffz-ui-menu-page .version-list ul {
margin-left: 20px
}
.ffz-ui-menu-page pre {
box-shadow: none !important;
white-space: pre-wrap;
@ -1255,7 +1298,7 @@ img.channel_background[src="null"] { display: none; }
.ffz-moderation-card .mod-controls:last-of-type button:last-of-type { margin-right: 0 }
.ffz-moderation-card .follow-button a {
text-indent: -9999px;
font-size: 0 !important;
padding-right: 0 !important;
}
@ -2795,7 +2838,7 @@ body:not(.ffz-tags-on-channel) .tw-title--tall { height: 60px }
/* Banned and Spoiler Games */
.ffz-game-spoilered .thumb .cap img,
body:not([data-current-path^="directory.csgo"]):not([data-current-path^="directory.game-directory"]):not([data-current-path^="directory.creative"]) .ffz-game-banned { display: none }
body:not([data-current-path^="directory.csgo"]):not([data-current-path^="directory.game"]):not([data-current-path^="directory.creative"]) .ffz-game-banned { display: none }
.ffz-game-spoilered .thumb .cap {
position: absolute !important; top: 0; left: 0; bottom: 0; right: 0;