1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-06-29 07:45:33 +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(); this._update_colors();
// Events for rebuilding 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'); Settings = utils.ember_lookup('controller:settings');
if ( Layout ) if ( Layout )
@ -654,7 +654,7 @@ FFZ.prototype._rebuild_colors = function() {
FFZ.prototype._update_colors = function(darkness_only) { FFZ.prototype._update_colors = function(darkness_only) {
// Update the lines. ALL of them. // 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'), Settings = utils.ember_lookup('controller:settings'),
is_dark = (Layout && Layout.get('isTheatreMode')) || (Settings && Settings.get('settings.darkMode')), 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(); f.rebuild_race_ui();
if ( f.settings.auto_theater ) { if ( f.settings.auto_theater ) {
var Layout = utils.ember_lookup('controller:layout'); var Layout = utils.ember_lookup('service:layout');
if ( Layout ) if ( Layout )
Layout.set('isTheatreMode', true); Layout.set('isTheatreMode', true);
} }

View file

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

View file

@ -33,6 +33,59 @@ FFZ.prototype.setup_profile_following = function() {
this._following_cache = {}; this._following_cache = {};
this._follower_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, // 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. // rather than making potentially hundreds of API requests.
var Following = utils.ember_resolve('model:kraken-channel-following'); var Following = utils.ember_resolve('model:kraken-channel-following');

View file

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

View file

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

View file

@ -1172,7 +1172,7 @@ FFZ.prototype._build_mod_card_history = function(msg, modcard, show_from) {
var raw_color = msg.color, var raw_color = msg.color,
colors = raw_color && this._handle_color(raw_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'), Settings = utils.ember_lookup('controller:settings'),
is_dark = (Layout && Layout.get('isTheatreMode')) || (Settings && Settings.get('settings.darkMode')); 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) { on_update: function(val) {
utils.toggle_cls('ffz-classic-player')(val); utils.toggle_cls('ffz-classic-player')(val);
var Layout = utils.ember_lookup('controller:layout'); var Layout = utils.ember_lookup('service:layout');
if ( Layout ) if ( Layout )
Layout.set('PLAYER_CONTROLS_HEIGHT', val ? 32 : 0); 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-player-volume')(this.settings.player_volume_bar);
utils.toggle_cls('ffz-classic-player')(this.settings.classic_player); 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 ) if ( Layout )
Layout.set('PLAYER_CONTROLS_HEIGHT', this.settings.classic_player ? 32 : 0); 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; s = this._$chatMessagesScroller;
Ember.run.next(function() { 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 ) if ( e.ffz_frozen || ! s || ! s.length )
return; 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, // Now that we've reset the tokens, if there's a line for this,
if ( last_ban._line ) 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 // 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. // amount of time from the last batch.
now = now || Date.now(); 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_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)); (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]; var room = f.rooms && f.rooms[msg.room];
if ( room ) { if ( room ) {
var chat_history = room.user_history = room.user_history || {}, 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({ new_msg = {
from: msg.from, from: msg.from,
tags: {'display-name': msg.tags && msg.tags['display-name']}, tags: {'display-name': msg.tags && msg.tags['display-name']},
message: msg.message, message: msg.message,
cachedTokens: msg.cachedTokens, cachedTokens: msg.cachedTokens,
style: msg.style, style: msg.style,
date: msg.date 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 ) if ( user_history.length > 20 )
user_history.shift(); user_history.shift();

View file

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

View file

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

View file

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

View file

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

View file

@ -17,14 +17,12 @@
/* Hide First Line */ /* Hide First Line */
.conversation-chat-lines > div:first-child:before, .conversation-chat-lines > div:first-child:before,
.chat-lines > div:first-of-type > .chat-line:before, .chat-line:first-of-type:before {
.chatReplay .chat-line:first-of-type:before {
border-top-color: transparent !important; border-top-color: transparent !important;
} }
/* Hide Last Line */ /* Hide Last Line */
.conversation-chat-lines > div:last-child:nth-child(odd):before, .conversation-chat-lines > div:last-child:nth-child(odd):before,
.chat-lines > div:last-of-type:nth-child(odd) > .chat-line:before, .chat-line:last-of-type:nth-child(odd):before {
.chatReplay .chat-line:last-of-type:nth-child(odd):before {
border-bottom-color: transparent !important; 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 ) if ( msgObject.cachedTokens )
return msgObject.cachedTokens; return msgObject.cachedTokens;
@ -489,6 +489,9 @@ FFZ.prototype.tokenize_chat_line = function(msgObject, prevent_notification, del
tokens = [msg]; tokens = [msg];
// Standard tokenization // Standard tokenization
if ( use_bits && helpers && helpers.tokenizeBits )
tokens = helpers.tokenizeBits(tokens);
if ( helpers && helpers.linkifyMessage ) { if ( helpers && helpers.linkifyMessage ) {
var labels = msgObject.labels || [], var labels = msgObject.labels || [],
mod_or_higher = labels.indexOf("owner") !== -1 || mod_or_higher = labels.indexOf("owner") !== -1 ||

View file

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

View file

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

View file

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

View file

@ -36,7 +36,7 @@ FFZ.settings_info.srl_races = {
FFZ.ws_on_close.push(function() { FFZ.ws_on_close.push(function() {
var controller = utils.ember_lookup('controller:channel'), 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'), current_host = controller && controller.get('hostModeTarget.id'),
need_update = false; need_update = false;
@ -56,7 +56,7 @@ FFZ.ws_on_close.push(function() {
FFZ.ws_commands.srl_race = function(data) { FFZ.ws_commands.srl_race = function(data) {
var controller = utils.ember_lookup('controller:channel'), 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'), current_host = controller && controller.get('hostModeTarget.id'),
need_update = false; need_update = false;
@ -92,7 +92,7 @@ FFZ.ws_commands.srl_race = function(data) {
FFZ.prototype.rebuild_race_ui = function() { FFZ.prototype.rebuild_race_ui = function() {
var controller = utils.ember_lookup('controller:channel'), 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'); hosted_id = controller && controller.get('hostModeTarget.id');
if ( ! this._cindex ) if ( ! this._cindex )
@ -111,7 +111,7 @@ FFZ.prototype.rebuild_race_ui = function() {
} else { } else {
if ( ! race_container ) { if ( ! race_container ) {
race_container = document.createElement('span'); race_container = utils.createElement('span', 'balloon-wrapper inline');
race_container.id = 'ffz-ui-race'; race_container.id = 'ffz-ui-race';
race_container.setAttribute('data-channel', channel_id); race_container.setAttribute('data-channel', channel_id);
@ -143,7 +143,7 @@ FFZ.prototype.rebuild_race_ui = function() {
} else { } else {
if ( ! race_container ) { if ( ! race_container ) {
race_container = document.createElement('span'); race_container = utils.createElement('span', 'balloon-wrapper inline');
race_container.id = 'ffz-ui-race'; race_container.id = 'ffz-ui-race';
race_container.setAttribute('data-channel', hosted_id); 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, pos = el.offsetLeft + el.offsetWidth,
race = this.srl_races[channel_id]; 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.id = 'ffz-race-popup';
popup.setAttribute('data-channel', channel_id); 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_kill = this._race_kill.bind(this);
this._popup_allow_parent = true; 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, var height = document.querySelector('.app-main.theatre') ? document.body.clientHeight - 300 : container.parentElement.offsetTop - 175,
controller = utils.ember_lookup('controller:channel'), 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!"); 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 += '<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 += '<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>'; 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 ) { if ( popup ) {
var tbody = popup.querySelector('tbody'), var tbody = popup.querySelector('tbody'),
timer = popup.querySelector('.heading span'), timer = popup.querySelector('.heading > span'),
info = popup.querySelector('.heading div'); info = popup.querySelector('.heading div');
tbody.innerHTML = ''; tbody.innerHTML = '';
@ -310,7 +309,7 @@ FFZ.prototype._update_race = function(container, not_timer) {
place = utils.place_string(ent.place), place = utils.place_string(ent.place),
comment = ent.comment ? utils.sanitize(ent.comment) : ""; 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 ) { 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; this._race_goal = race.goal;
var game = utils.sanitize(race.game), 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 ) if ( ! elapsed )

View file

@ -9,6 +9,10 @@ var sanitize_el = document.createElement('span'),
return sanitize_el.innerHTML; 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) { escape_regex = RegExp.escape || function(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}, },
@ -388,6 +392,7 @@ module.exports = FFZ.utils = {
}, },
sanitize: sanitize, sanitize: sanitize,
unquote_attr: unquote_attr,
quote_attr: quote_attr, quote_attr: quote_attr,
date_string: function(date) { 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, .ember-chat-container.dark .ffz-ui-toggle svg.svg-emoticons path,
.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, .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, .ember-chat-container.dark .ffz-ui-toggle:hover svg.svg-emoticons path,
.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, .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); } .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 { #ffz-race-popup {
position: absolute; position: absolute;
bottom: 0; display: block;
background-image: url("//cdn.frankerfacez.com/script/zreknarf-bg.png"); background-image: url("//cdn.frankerfacez.com/script/zreknarf-bg.png");
background-repeat: no-repeat; background-repeat: no-repeat;
padding: 1rem;
background-position: 115% 110%; background-position: 115% 110%;
} }
#ffz-race-popup.right { right: 10px; } #ffz-race-popup.right { right: 10px; }
#ffz-race-popup .heading { #ffz-race-popup .heading {
margin: -20px -20px 20px; margin: -1rem -1rem 1rem;
width: 340px; height: 65px; height: 65px;
position: relative; position: relative;
} }
#ffz-race-popup .heading div { #ffz-race-popup .heading div {
padding: 10px 0 0 20px; padding: 0 1rem;
max-width: 240px; }
#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 { #ffz-race-popup .heading h2 {
max-width: 240px;
font-size: 1.5em; font-size: 1.5em;
padding-bottom: 5px; padding-bottom: 5px;
display: block; display: block;
width: 240px; width: 200px;
max-height: 45px; margin-bottom: 0;
overflow: hidden;
text-overflow: ellipsis;
} }
#ffz-race-popup .heading span { #ffz-race-popup .heading > span {
line-height: 30px; line-height: 30px;
position: absolute; position: absolute;
top: 17.5px; top: 7.5px;
right: 20px; right: 1rem;
padding: 0 5px; padding: 0 5px;
background: rgba(0,0,0,0.5); background: rgba(0,0,0,0.5);
color: #fff; color: #fff;
border-radius: 5px; border-radius: 5px;
} }
#ffz-race-popup .right { text-align: right; } #ffz-race-popup .right {
padding-top: 0;
text-align: right;
}
#ffz-race-popup .table { #ffz-race-popup .table {
overflow-y: auto; overflow-y: auto;
border-bottom: 1px solid;
margin-bottom: 1rem;
} }
#ffz-race-popup table { #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; } .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 { .chat-menu-content.collapsable .heading span.right {
padding-right: 15px; 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); 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 { .ffz-ui-menu-page pre {
box-shadow: none !important; box-shadow: none !important;
white-space: pre-wrap; 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 .mod-controls:last-of-type button:last-of-type { margin-right: 0 }
.ffz-moderation-card .follow-button a { .ffz-moderation-card .follow-button a {
text-indent: -9999px; font-size: 0 !important;
padding-right: 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 */ /* Banned and Spoiler Games */
.ffz-game-spoilered .thumb .cap img, .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 { .ffz-game-spoilered .thumb .cap {
position: absolute !important; top: 0; left: 0; bottom: 0; right: 0; position: absolute !important; top: 0; left: 0; bottom: 0; right: 0;