mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-06-27 21:05:53 +00:00
3.5.527. Tooltips! Lots of changes to how link tooltips render. And some stuff about the dark theme I guess.
This commit is contained in:
parent
231e2839e8
commit
9e845b171e
14 changed files with 534 additions and 181 deletions
|
@ -1,3 +1,19 @@
|
|||
<div class="list-header">3.5.527 <time datetime="2017-09-25">(2017-09-25)</time></div>
|
||||
<ul class="chat-menu-content menu-side-padding">
|
||||
<li>Changed: More tweaks to tooltip rendering to support backend improvements.</li>
|
||||
</ul>
|
||||
|
||||
<div class="list-header">3.5.526 <time datetime="2017-09-22">(2017-09-22)</time></div>
|
||||
<ul class="chat-menu-content menu-side-padding">
|
||||
<li>Changed: Minor tweaks to tooltip rendering to support improvements to the backend.</li>
|
||||
</ul>
|
||||
|
||||
<div class="list-header">3.5.525 <time datetime="2017-09-20">(2017-09-20)</time></div>
|
||||
<ul class="chat-menu-content menu-side-padding">
|
||||
<li>Fixed: Twitch's native dark theme breaking the re-colored site header.</li>
|
||||
<li>Fixed: Take control of Twitch's native dark theme when enabling or disabling FFZ's dark theme.</li>
|
||||
</ul>
|
||||
|
||||
<div class="list-header">3.5.524 <time datetime="2017-09-15">(2017-09-15)</time></div>
|
||||
<ul class="chat-menu-content menu-side-padding">
|
||||
<li>Fixed: Tooltips for global emotes not saying where they're from.</li>
|
||||
|
@ -38,38 +54,5 @@
|
|||
<li>Fixed: Bug with rich content attached to chat messages not getting removed when a message is timed out.</li>
|
||||
</ul>
|
||||
|
||||
<div class="list-header">3.5.517 <time datetime="2017-09-02">(2017-09-02)</time></div>
|
||||
<ul class="chat-menu-content menu-side-padding">
|
||||
<li>Changed: Dark theme CSS tweak for the directory.</li>
|
||||
</ul>
|
||||
|
||||
<div class="list-header">3.5.516 <time datetime="2017-09-01">(2017-09-01)</time></div>
|
||||
<ul class="chat-menu-content menu-side-padding">
|
||||
<li>Fixed: Typo in video url regular expression.</li>
|
||||
</ul>
|
||||
|
||||
<div class="list-header">3.5.515 <time datetime="2017-09-01">(2017-09-01)</time></div>
|
||||
<ul class="chat-menu-content menu-side-padding">
|
||||
<li>Added: Option to disable rich content in chat.</li>
|
||||
<li>Changed: Add support for rich content in chat. This includes shared purchases, clip information, and video information.</li>
|
||||
<li>API Added: <code>replaces</code> field to emoticons to allow extension emotes to replace Twitch emotes.</li>
|
||||
</ul>
|
||||
|
||||
<div class="list-header">3.5.514 <time datetime="2017-09-01">(2017-09-01)</time></div>
|
||||
<ul class="chat-menu-content menu-side-padding">
|
||||
<li>Fixed: Schedule parsing issue with null values.</li>
|
||||
</ul>
|
||||
|
||||
<div class="list-header">3.5.513 <time datetime="2017-08-22">(2017-08-22)</time></div>
|
||||
<ul class="chat-menu-content menu-side-padding">
|
||||
<li>Fixed: Dark CSS tweak for Chat Replay.</li>
|
||||
</ul>
|
||||
|
||||
<div class="list-header">3.5.512 <time datetime="2017-08-18">(2017-08-18)</time></div>
|
||||
<ul class="chat-menu-content menu-side-padding">
|
||||
<li>Fixed: Blocked Games feature not properly hiding channels from the social bar.</li>
|
||||
<li>Fixed: Dark CSS tweaks for the dashboard.</li>
|
||||
</ul>
|
||||
|
||||
<div class="list-header" id="ffz-old-news-button"><a href="#">View Older</a></div>
|
||||
<div id="ffz-old-news"></div>
|
1
dark.css
1
dark.css
|
@ -756,6 +756,7 @@ body.ffz-dark:not([data-page="teams#show"]),
|
|||
}
|
||||
|
||||
/* Hide the chat Dark Mode control */
|
||||
.ffz-dark #theme-toggle,
|
||||
.ffz-dark .toggle-darkmode { display: none; }
|
||||
|
||||
/* Chat Text Contrast */
|
||||
|
|
|
@ -1,3 +1,36 @@
|
|||
<div class="list-header">3.5.517 <time datetime="2017-09-02">(2017-09-02)</time></div>
|
||||
<ul class="chat-menu-content menu-side-padding">
|
||||
<li>Changed: Dark theme CSS tweak for the directory.</li>
|
||||
</ul>
|
||||
|
||||
<div class="list-header">3.5.516 <time datetime="2017-09-01">(2017-09-01)</time></div>
|
||||
<ul class="chat-menu-content menu-side-padding">
|
||||
<li>Fixed: Typo in video url regular expression.</li>
|
||||
</ul>
|
||||
|
||||
<div class="list-header">3.5.515 <time datetime="2017-09-01">(2017-09-01)</time></div>
|
||||
<ul class="chat-menu-content menu-side-padding">
|
||||
<li>Added: Option to disable rich content in chat.</li>
|
||||
<li>Changed: Add support for rich content in chat. This includes shared purchases, clip information, and video information.</li>
|
||||
<li>API Added: <code>replaces</code> field to emoticons to allow extension emotes to replace Twitch emotes.</li>
|
||||
</ul>
|
||||
|
||||
<div class="list-header">3.5.514 <time datetime="2017-09-01">(2017-09-01)</time></div>
|
||||
<ul class="chat-menu-content menu-side-padding">
|
||||
<li>Fixed: Schedule parsing issue with null values.</li>
|
||||
</ul>
|
||||
|
||||
<div class="list-header">3.5.513 <time datetime="2017-08-22">(2017-08-22)</time></div>
|
||||
<ul class="chat-menu-content menu-side-padding">
|
||||
<li>Fixed: Dark CSS tweak for Chat Replay.</li>
|
||||
</ul>
|
||||
|
||||
<div class="list-header">3.5.512 <time datetime="2017-08-18">(2017-08-18)</time></div>
|
||||
<ul class="chat-menu-content menu-side-padding">
|
||||
<li>Fixed: Blocked Games feature not properly hiding channels from the social bar.</li>
|
||||
<li>Fixed: Dark CSS tweaks for the dashboard.</li>
|
||||
</ul>
|
||||
|
||||
<div class="list-header">3.5.511 <time datetime="2017-08-12">(2017-08-12)</time></div>
|
||||
<ul class="chat-menu-content menu-side-padding">
|
||||
<li>Fixed: Bits rendering after Twitch removed the Ember bits-tags service.</li>
|
||||
|
|
|
@ -70,6 +70,7 @@ func (backend *backendInfo) UnsealRequest(form url.Values) (url.Values, error) {
|
|||
dec := base64.NewDecoder(base64.URLEncoding, strings.NewReader(nonceString))
|
||||
count, err := dec.Read(nonce[:])
|
||||
if err != nil {
|
||||
fmt.Println("Error reading nonce");
|
||||
Statistics.BackendVerifyFails++
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -145,6 +145,7 @@ FFZ.prototype.setup_colors = function() {
|
|||
|
||||
// Events for rebuilding colors.
|
||||
var Layout = utils.ember_lookup('service:layout'),
|
||||
ThemeManager = utils.ember_lookup('service:theme-manager'),
|
||||
Settings = utils.ember_settings();
|
||||
|
||||
if ( Layout )
|
||||
|
@ -153,7 +154,11 @@ FFZ.prototype.setup_colors = function() {
|
|||
if ( Settings )
|
||||
Settings.addObserver("darkMode", this._update_colors.bind(this, true))
|
||||
|
||||
this._color_old_darkness = (Layout && Layout.get('isTheatreMode')) || (Settings && Settings.get('darkMode'));
|
||||
if ( ThemeManager )
|
||||
ThemeManager.addObserver("themes.activeTheme", this._update_colors.bind(this, true));
|
||||
|
||||
|
||||
this._color_old_darkness = (ThemeManager && ThemeManager.get('themes.activeTheme') === 'theme--dark') || (Layout && Layout.get('isTheatreMode')) || (Settings && Settings.get('darkMode'));
|
||||
}
|
||||
|
||||
|
||||
|
@ -672,8 +677,9 @@ FFZ.prototype._rebuild_colors = function() {
|
|||
FFZ.prototype._update_colors = function(darkness_only) {
|
||||
// Update the lines. ALL of them.
|
||||
var Layout = utils.ember_lookup('service:layout'),
|
||||
ThemeManager = utils.ember_lookup('service:theme-manager'),
|
||||
|
||||
is_dark = (Layout && Layout.get('isTheatreMode')) || this.settings.get_twitch("darkMode"),
|
||||
is_dark = (ThemeManager && ThemeManager.get('themes.activeTheme') === 'theme--dark') || (Layout && Layout.get('isTheatreMode')) || this.settings.get_twitch("darkMode"),
|
||||
cr_dark = this.settings.dark_twitch || (Layout && Layout.get('isTheatreMode'));
|
||||
|
||||
if ( darkness_only && this._color_old_darkness === is_dark )
|
||||
|
|
|
@ -47,7 +47,7 @@ module.exports = FrankerFaceZ.constants = {
|
|||
|
||||
CHAT_COLORS: ["#FF0000", "#0000FF", "#008000", "#B22222", "#FF7F50", "#9ACD32", "#FF4500", "#2E8B57", "#DAA520", "#D2691E", "#5F9EA0", "#1E90FF", "#FF69B4", "#8A2BE2", "#00FF7F"],
|
||||
|
||||
TOOLTIP_DISTANCE: 50,
|
||||
TOOLTIP_DISTANCE: 100,
|
||||
|
||||
SEPARATORS: SEPARATORS,
|
||||
SPLITTER: SPLITTER,
|
||||
|
|
|
@ -399,8 +399,27 @@ FFZ.settings_info.link_info = {
|
|||
no_bttv: 6,
|
||||
|
||||
name: "Link Information <span>Beta</span>",
|
||||
help: "Check links against known bad websites, unshorten URLs, and show YouTube info."
|
||||
};
|
||||
help: "Check links against known bad websites, unshorten URLs, and show YouTube info.",
|
||||
|
||||
on_update: function(val) {
|
||||
// Update every visible chat link and, possibly, wipe the link info cache.
|
||||
if ( ! val ) {
|
||||
this._link_data = {};
|
||||
jQuery('.unsafe-link').removeClass('unsafe-link');
|
||||
|
||||
} else {
|
||||
var links = document.querySelectorAll('.chat-link[data-url]');
|
||||
for(var i=0,l=links.length; i < l; i++) {
|
||||
var link = links[i],
|
||||
url = link.dataset.url,
|
||||
info = this.get_link_info(url);
|
||||
|
||||
if ( info && info.unsafe )
|
||||
link.classList.add('unsafe-link');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
FFZ.settings_info.link_image_hover = {
|
||||
|
@ -412,8 +431,8 @@ FFZ.settings_info.link_image_hover = {
|
|||
no_mobile: true,
|
||||
|
||||
name: "Image Preview",
|
||||
help: "Display image thumbnails for links to Imgur and YouTube."
|
||||
};
|
||||
help: "Display images associated with links to known services such as YouTube, Imgur, and Twitter."
|
||||
};
|
||||
|
||||
|
||||
FFZ.settings_info.emote_image_hover = {
|
||||
|
@ -439,9 +458,9 @@ FFZ.settings_info.image_hover_all_domains = {
|
|||
no_bttv: 6,
|
||||
no_mobile: true,
|
||||
|
||||
name: "Image Preview - All Domains",
|
||||
help: "<i>Requires Image Preview.</i> Attempt to show an image preview for any URL ending in the appropriate extension. <b>Warning: This may be used to leak your IP address to malicious users.</b>"
|
||||
};
|
||||
name: "Image Preview - NSFW",
|
||||
help: "<i>Requires Image Preview.</i> Display images from all sources, including images that are tagged as unsafe or without rating information."
|
||||
};
|
||||
|
||||
|
||||
FFZ.settings_info.chat_rows = {
|
||||
|
@ -949,6 +968,7 @@ FFZ.prototype._modify_chat_line = function(component, is_vod) {
|
|||
var f = this,
|
||||
Layout = utils.ember_lookup('service:layout'),
|
||||
Chat = utils.ember_lookup('controller:chat'),
|
||||
ThemeManager = utils.ember_lookup('service:theme-manager'),
|
||||
PinnedCheers = utils.ember_lookup('service:bits-pinned-cheers'),
|
||||
Settings = utils.ember_settings();
|
||||
|
||||
|
@ -1114,7 +1134,7 @@ FFZ.prototype._modify_chat_line = function(component, is_vod) {
|
|||
|
||||
raw_color = this.get(is_recipient ? 'msgObject.toColor' : 'msgObject.color'),
|
||||
|
||||
is_dark = (Layout && Layout.get('isTheatreMode')) || (is_replay ? f.settings.dark_twitch : (Settings && Settings.get('darkMode'))),
|
||||
is_dark = (ThemeManager && ThemeManager.get('themes.activeTheme') === 'theme--dark') || (Layout && Layout.get('isTheatreMode')) || (is_replay ? f.settings.dark_twitch : (Settings && Settings.get('darkMode'))),
|
||||
is_replay = this.get('ffz_is_replay'),
|
||||
|
||||
colors = raw_color && f._handle_color(raw_color),
|
||||
|
@ -1402,7 +1422,7 @@ FFZ.prototype._modify_chat_line = function(component, is_vod) {
|
|||
var raw_color = this.get('msgObject.color'),
|
||||
colors = raw_color && f._handle_color(raw_color),
|
||||
is_replay = this.get('ffz_is_replay'),
|
||||
is_dark = (Layout && Layout.get('isTheatreMode')) || (is_replay ? f.settings.dark_twitch : (Settings && Settings.get('darkMode')));
|
||||
is_dark = (ThemeManager && ThemeManager.get('themes.activeTheme') === 'theme--dark') || (Layout && Layout.get('isTheatreMode')) || (is_replay ? f.settings.dark_twitch : (Settings && Settings.get('darkMode')));
|
||||
|
||||
if ( raw_color )
|
||||
output = '<span class="message has-color' + (is_replay ? ' replay-color' : '') + '" style="color:' + (is_dark ? colors[1] : colors[0]) + '" data-color="' + raw_color + '">';
|
||||
|
|
|
@ -1616,9 +1616,10 @@ FFZ.prototype._build_mod_card_history = function(msg, modcard, show_from, ts_cli
|
|||
colors = raw_color && this._handle_color(raw_color),
|
||||
|
||||
Layout = utils.ember_lookup('service:layout'),
|
||||
ThemeManager = utils.ember_lookup('service:theme-manager'),
|
||||
Settings = utils.ember_settings(),
|
||||
|
||||
is_dark = (Layout && Layout.get('isTheatreMode')) || this.settings.get_twitch("darkMode");
|
||||
is_dark = (ThemeManager && ThemeManager.get('themes.activeTheme') === 'theme--dark') || (Layout && Layout.get('isTheatreMode')) || this.settings.get_twitch("darkMode");
|
||||
|
||||
|
||||
// Styling
|
||||
|
|
|
@ -218,7 +218,7 @@ FFZ.settings_info.top_nav_color = {
|
|||
val = color.toCSS();
|
||||
}
|
||||
|
||||
var out = '.top-nav__menu,.top-nav__drawer-anchor,.top-nav__logo{background-color:' + val + '}';
|
||||
var out = '.theme--dark .top-nav__menu,.top-nav__menu,.top-nav__drawer-anchor,.top-nav__logo{background-color:' + val + '}';
|
||||
|
||||
if ( color.luminance() > 0.2 ) {
|
||||
out += '.top-nav__search .form__icon svg,.top-nav .notification-center__icon svg,.top-nav .prime-logo-crown.prime-logo-crown--white svg,.top-nav__logo svg path, .top-nav__overflow svg path{fill: #000}' +
|
||||
|
|
|
@ -61,7 +61,7 @@ FFZ.channel_metadata = {};
|
|||
|
||||
// Version
|
||||
var VER = FFZ.version_info = {
|
||||
major: 3, minor: 5, revision: 524,
|
||||
major: 3, minor: 5, revision: 527,
|
||||
toString: function() {
|
||||
return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || "");
|
||||
}
|
||||
|
|
303
src/tokenize.js
303
src/tokenize.js
|
@ -10,6 +10,7 @@ var FFZ = window.FrankerFaceZ,
|
|||
|
||||
HOP = Object.prototype.hasOwnProperty,
|
||||
|
||||
TOOLTIP_VERSION = 2,
|
||||
FAV_MARKER = '<span class="ffz-favorite"></span>',
|
||||
|
||||
EXPLANATION_WARN = '<hr>This link has been sent to you via a whisper rather than standard chat, and has not been checked or approved of by any moderators or staff members. Please treat this link with caution and do not visit it if you do not trust the sender.',
|
||||
|
@ -20,6 +21,7 @@ var FFZ = window.FrankerFaceZ,
|
|||
|
||||
LINK = /(?:https?:\/\/)?(?:[-a-zA-Z0-9@:%_\+~#=]+\.)+[a-z]{2,6}\b(?:[-a-zA-Z0-9@:%_\+.~#?&\/\/=()]*)/g,
|
||||
|
||||
TIME_REPLACER = /<time\s+datetime=(["'])([^>]+?)\1[^>]*>(.*?)<\/time>/i,
|
||||
CLIP_URL = /^(?:https?:\/\/)?clips\.twitch\.tv\/(\w+?\/?\w*?)(?:\/edit)?(?:[\?#]|$)/,
|
||||
VIDEO_URL = /^(?:https?:\/\/)?(?:www\.)?twitch\.tv\/(?:\w+\/v|videos)\/(\w+)$/,
|
||||
FFZ_EMOTE_URL = /^(?:https?:\/\/)?(?:www\.)?frankerfacez\.com\/emoticon\/(\d+)(?:-\w*)?$/,
|
||||
|
@ -51,21 +53,6 @@ var FFZ = window.FrankerFaceZ,
|
|||
|
||||
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>';
|
||||
},
|
||||
|
||||
load_link_data = function(href, success, data) {
|
||||
if ( ! success )
|
||||
return;
|
||||
|
||||
this._link_data[href] = data;
|
||||
//data.unsafe = false;
|
||||
|
||||
if ( ! this.settings.link_info )
|
||||
return;
|
||||
|
||||
// If this link is unsafe, add the unsafe-link class to all instances of the link.
|
||||
if ( data.unsafe )
|
||||
jQuery('a.chat-link[data-url="' + href + '"]').addClass('unsafe-link');
|
||||
};
|
||||
|
||||
|
||||
|
@ -348,43 +335,6 @@ FFZ.prototype.format_display_name = function(display_name, user_id, disable_alia
|
|||
// Twitch Emote Data
|
||||
// ---------------------
|
||||
|
||||
/*FFZ.prototype.load_twitch_emote_data = function(tries) {
|
||||
var f = this;
|
||||
f._twitch_set_to_channel[0] = "--global--";
|
||||
f._twitch_set_to_channel[33] = "--turbo-faces--";
|
||||
f._twitch_set_to_channel[42] = "--turbo-faces--";
|
||||
f._twitch_set_to_channel[19194] = "--prime--";
|
||||
f._twitch_set_to_channel[19151] = "--curse--";
|
||||
|
||||
/*this.log("Loading Twitch Emote Data (Try " + (tries || 0) + ")");
|
||||
|
||||
jQuery.ajax(constants.SERVER + "twitch_emotes.json")
|
||||
.done(function(data) {
|
||||
f.log("Loaded Twitch Emote Data", data);
|
||||
for(var set_id in data) {
|
||||
var set = data[set_id],
|
||||
old_id = f._twitch_set_to_channel[set_id];
|
||||
if ( ! set )
|
||||
continue;
|
||||
|
||||
if ( ! old_id || old_id.indexOf('--') === -1 )
|
||||
f._twitch_set_to_channel[set_id] = set.name;
|
||||
|
||||
for(var i=0, l = set.emotes.length; i < l; i++)
|
||||
f._twitch_emote_to_set[set.emotes[i]] = set_id;
|
||||
}
|
||||
|
||||
}).fail(function(data) {
|
||||
f.log("Error loading Twitch Emote Data", data);
|
||||
if ( data.status === 404 )
|
||||
return;
|
||||
|
||||
tries = (tries || 0) + 1;
|
||||
if ( tries < 10 )
|
||||
setTimeout(f.load_twitch_emote_data.bind(f, tries), 1000);
|
||||
});*
|
||||
}*/
|
||||
|
||||
var UNSET = {};
|
||||
|
||||
FFZ.prototype.get_twitch_set_for = function(emote_id, callback) {
|
||||
|
@ -492,6 +442,149 @@ FFZ.prototype.get_twitch_set = function(set_id, callback) {
|
|||
// Tooltip Rendering
|
||||
// ---------------------
|
||||
|
||||
FFZ.prototype.clean_link_info = function() {
|
||||
clearTimeout(this._link_info_cleaner);
|
||||
|
||||
var now = Date.now(),
|
||||
obj = {};
|
||||
|
||||
for(var url in this._link_data) {
|
||||
var data = this._link_data[url];
|
||||
if ( data && (! data[1] || now <= data[1] ) )
|
||||
obj[url] = data;
|
||||
}
|
||||
|
||||
this._link_data = obj;
|
||||
this._link_info_cleaner = setTimeout(this.clean_link_info.bind(this), 120000);
|
||||
}
|
||||
|
||||
|
||||
FFZ.prototype.get_link_info = function(url, no_promises) {
|
||||
var f = this,
|
||||
info = this._link_data[url],
|
||||
expires = info && info[1],
|
||||
|
||||
li = this.settings.link_info;
|
||||
|
||||
if ( ! li || (expires && Date.now() > expires) )
|
||||
info = this._link_data[url] = null;
|
||||
|
||||
if ( ! li )
|
||||
return null;
|
||||
|
||||
if ( info && info[0] )
|
||||
return info[2];
|
||||
|
||||
if ( no_promises )
|
||||
return null;
|
||||
|
||||
else if ( info )
|
||||
return new Promise(function(resolve, reject) {
|
||||
info[2].push([resolve, reject]);
|
||||
});
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
info = f._link_data[url] = [false, null, [[resolve, reject]]];
|
||||
|
||||
var link_timer,
|
||||
resolve = function(success, data) {
|
||||
clearTimeout(link_timer);
|
||||
|
||||
// If it's a failure and we already finished, just quit.
|
||||
if ( ! f.settings.link_info || (info[0] && ! success) )
|
||||
return;
|
||||
|
||||
var callbacks = ! info[0] && info[2];
|
||||
f._link_data[url] = [true, Date.now() + 120000, success ? data : null];
|
||||
|
||||
if ( data && data.unsafe )
|
||||
jQuery('a[data-url="' + url + '"]').addClass('unsafe-link');
|
||||
|
||||
if ( callbacks )
|
||||
for(var i=0; i < callbacks.length; i++)
|
||||
callbacks[i][success ? 0 : 1](data);
|
||||
|
||||
if ( ! f._link_info_cleaner )
|
||||
f.clean_link_info();
|
||||
};
|
||||
|
||||
link_timer = setTimeout(resolve.bind(this, false, 'A request timed out while trying to load information about this link.'), 15000);
|
||||
f.ws_send("get_link", url, resolve, true);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
FFZ.prototype.render_link_tooltip = function(data, el) {
|
||||
var version = data.v || 1;
|
||||
if ( version > TOOLTIP_VERSION )
|
||||
return '';
|
||||
|
||||
var content = data.content || data.html || '';
|
||||
|
||||
if ( content )
|
||||
content = content.replace(TIME_REPLACER, function(match, junk, timestamp, old) {
|
||||
var now = Date.now(),
|
||||
posted_at = utils.parse_date(timestamp),
|
||||
time_ago = posted_at && (now - posted_at) / 1000;
|
||||
|
||||
if ( time_ago < 86400 )
|
||||
old = utils.full_human_time(time_ago);
|
||||
else if ( posted_at )
|
||||
old = posted_at.toLocaleString();
|
||||
|
||||
return '<time timestamp="' + utils.sanitize(timestamp) + '">' + utils.sanitize(old) + '</time>';
|
||||
});
|
||||
|
||||
|
||||
if ( data.urls && data.urls.length > 1 ) {
|
||||
var last_url = data.urls[data.urls.length-1];
|
||||
content += (content.length ? '<hr>' : '') + 'Destination: ' + utils.sanitize(last_url[1]);
|
||||
}
|
||||
|
||||
if ( data.unsafe ) {
|
||||
var reasons = _.pluck(data.urls, 2).filter((function(x){return x})).uniq().join(", ");
|
||||
content = "Caution: This URL is on Google's Safe Browsing list for: " +
|
||||
utils.sanitize(reasons.toLowerCase()) + (content.length ? '<hr>' + content : '');
|
||||
}
|
||||
|
||||
if ( el && el.classList.contains('warn-link') )
|
||||
content += (content.length ? '<hr>' : '') + EXPLANATION_WARN;
|
||||
|
||||
var show_image = this.settings.link_image_hover && (data.image_safe || this.settings.image_hover_all_domains);
|
||||
|
||||
if ( show_image ) {
|
||||
if ( data.image )
|
||||
if ( data.image_iframe )
|
||||
content = image_iframe(data.image) + content;
|
||||
else
|
||||
content = '<img class="emoticon ffz-image-hover" src="' + utils.quote_attr(data.image) + '">' + content;
|
||||
|
||||
} else if ( content.length )
|
||||
content = content.replace(/<!--MS-->.*<!--ME-->/g, '');
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
|
||||
FFZ.prototype.render_tooltip_class = function(el) {
|
||||
var f = this,
|
||||
func = function() {
|
||||
if ( this.classList.contains('chat-link') ) {
|
||||
// TODO: A lot of shit. Lookup data.
|
||||
var url = this.getAttribute("data-url"),
|
||||
data = url && f.get_link_info(url, true);
|
||||
|
||||
if ( data )
|
||||
return data.tooltip_class;
|
||||
}
|
||||
|
||||
return this.dataset.tooltipClass;
|
||||
};
|
||||
|
||||
return el ? func(el) : func;
|
||||
}
|
||||
|
||||
|
||||
FFZ.prototype.render_tooltip = function(el) {
|
||||
var f = this,
|
||||
func = function() {
|
||||
|
@ -646,39 +739,47 @@ FFZ.prototype.render_tooltip = function(el) {
|
|||
|
||||
} else if ( this.classList.contains('chat-link') ) {
|
||||
// TODO: A lot of shit. Lookup data.
|
||||
var url = this.getAttribute("data-url"),
|
||||
data = url && f._link_data[url],
|
||||
var t = this,
|
||||
url = this.getAttribute("data-url"),
|
||||
data = url && f.get_link_info(url);
|
||||
|
||||
preview_url = null,
|
||||
preview_iframe = true,
|
||||
image = '',
|
||||
text = '';
|
||||
|
||||
if ( ! url )
|
||||
return;
|
||||
|
||||
// Do we have data?
|
||||
if ( data && data !== true ) {
|
||||
text = data.html;
|
||||
preview_url = data.image;
|
||||
preview_iframe = data.image_iframe !== undefined ? data.image_iframe : true;
|
||||
} else
|
||||
preview_url = is_image(url, f.settings.image_hover_all_domains) ? url : null;
|
||||
|
||||
if ( f.settings.link_image_hover && preview_url )
|
||||
if ( preview_iframe )
|
||||
image = image_iframe(url);
|
||||
else
|
||||
image = '<img class="emoticon ffz-image-hover" src="' + utils.quote_attr(preview_url) + '">';
|
||||
|
||||
// If it's not a deleted link, don't waste time showing the URL in the tooltip.
|
||||
if ( this.classList.contains('deleted-link') )
|
||||
text = utils.sanitize(url);
|
||||
return utils.sanitize(url || '');
|
||||
|
||||
if ( this.classList.contains('warn-link') )
|
||||
text += EXPLANATION_WARN;
|
||||
if ( ! url || ! data )
|
||||
return '';
|
||||
|
||||
return image + text; //`${image}${text}`;
|
||||
if ( data instanceof Promise ) {
|
||||
var tt_id = FFZ._sc_followed_tooltip_id++,
|
||||
replacer = function(data, tooltip_class) {
|
||||
var el = document.querySelector('.ffz-async-tooltip[data-id="' + tt_id + '"]'),
|
||||
container = el && el.parentElement.parentElement;
|
||||
if ( ! el )
|
||||
return;
|
||||
|
||||
if ( ! data )
|
||||
jQuery(container).remove();
|
||||
|
||||
if ( tooltip_class )
|
||||
container.classList.add(tooltip_class);
|
||||
|
||||
el.outerHTML = data;
|
||||
};
|
||||
|
||||
data.then(function(data) {
|
||||
if ( data )
|
||||
replacer(f.render_link_tooltip(data, t), data.tooltip_class);
|
||||
else
|
||||
replacer(null);
|
||||
|
||||
}).catch(function(err) {
|
||||
replacer(utils.sanitize(err || ''));
|
||||
});
|
||||
|
||||
return '<div class="ffz-async-tooltip" data-id="' + tt_id + '"></div>';
|
||||
|
||||
} else
|
||||
return f.render_link_tooltip(data, this);
|
||||
}
|
||||
|
||||
f.log("Unable to Build Tooltip For: " + this.className, this);
|
||||
|
@ -1379,43 +1480,9 @@ FFZ.prototype.render_token = function(render_links, warn_links, render_bits, tok
|
|||
// Web Link
|
||||
cls = 'chat-link';
|
||||
|
||||
if ( this.settings.link_info ) {
|
||||
if (!( this._link_data && this._link_data[href] )) {
|
||||
this._link_data = this._link_data || {};
|
||||
this._link_data[href] = true;
|
||||
|
||||
var success = load_link_data.bind(this, href),
|
||||
clip_info = CLIP_URL.exec(href),
|
||||
video_info = VIDEO_URL.exec(href);
|
||||
|
||||
if ( clip_info ) {
|
||||
var Clips = utils.ember_lookup('service:clips');
|
||||
Clips && Clips.fetchClipBySlug(clip_info[1]).then(function(data) {
|
||||
data &&
|
||||
success(true, {
|
||||
image: data.thumbnails.medium,
|
||||
image_iframe: false,
|
||||
html: '<span class="ffz-clip-title">' + utils.sanitize(data.title) + '</span>' +
|
||||
'Channel: ' + utils.sanitize(data.broadcaster_display_name) +
|
||||
'<br>Game: ' + utils.sanitize(data.game)
|
||||
});
|
||||
});
|
||||
|
||||
} else if ( video_info ) {
|
||||
utils.api.get("videos/" + video_info[1], undefined, {version: 5})
|
||||
.then(function(data) {
|
||||
success(true, {
|
||||
image: data.preview.large,
|
||||
image_iframe: false,
|
||||
html: '<span class="ffz-clip-title">' + utils.sanitize(data.title) + ' [' + utils.time_to_string(data.length) + ']</span>' +
|
||||
'Channel: ' + utils.sanitize(data.channel.display_name) +
|
||||
'<br>Game: ' + utils.sanitize(data.game)
|
||||
})});
|
||||
|
||||
} else
|
||||
this.ws_send("get_link", href, success);
|
||||
}
|
||||
}
|
||||
var info = this.get_link_info(href);
|
||||
if ( info && info.unsafe )
|
||||
cls += ' unsafe-link';
|
||||
}
|
||||
|
||||
// Deleted Links
|
||||
|
|
|
@ -114,6 +114,12 @@ FFZ.settings_info.twitch_chat_dark = {
|
|||
};
|
||||
|
||||
|
||||
FFZ.settings_info.twitch_theme = {
|
||||
value: '',
|
||||
visible: false
|
||||
};
|
||||
|
||||
|
||||
FFZ.settings_info.dark_twitch = {
|
||||
type: "boolean",
|
||||
value: false,
|
||||
|
@ -139,14 +145,25 @@ FFZ.settings_info.dark_twitch = {
|
|||
|
||||
(this.is_clips ? document.querySelector('html') : document.body).classList.toggle("ffz-dark", val);
|
||||
|
||||
var Settings = utils.ember_settings();
|
||||
var Settings = utils.ember_settings(),
|
||||
ThemeManager = utils.ember_lookup('service:theme-manager');
|
||||
|
||||
if ( val ) {
|
||||
this._load_dark_css();
|
||||
Settings && this.settings.set('twitch_chat_dark', Settings.get('darkMode'));
|
||||
Settings && Settings.set('darkMode', true);
|
||||
} else
|
||||
Settings && Settings.set('darkMode', this.settings.twitch_chat_dark);
|
||||
if ( ThemeManager ) {
|
||||
this.settings.set('twitch_theme', ThemeManager.get('themes.activeTheme'));
|
||||
ThemeManager.set('themes.activeTheme', 'theme--dark');
|
||||
}
|
||||
if ( Settings ) {
|
||||
this.settings.set('twitch_chat_dark', Settings.get('darkMode'));
|
||||
Settings.set('darkMode', true);
|
||||
}
|
||||
} else {
|
||||
if ( ThemeManager )
|
||||
ThemeManager.set('themes.activeTheme', this.settings.twitch_theme);
|
||||
if ( Settings )
|
||||
Settings.set('darkMode', this.settings.twitch_chat_dark);
|
||||
}
|
||||
|
||||
// Try coloring chat replay
|
||||
window.jQuery && jQuery('.chatReplay').toggleClass('dark', val || false);
|
||||
|
@ -204,15 +221,13 @@ FFZ.prototype.setup_dark = function() {
|
|||
if ( ! this.settings.dark_twitch )
|
||||
return;
|
||||
|
||||
var Settings = utils.ember_settings();
|
||||
if ( Settings ) {
|
||||
try {
|
||||
Settings.set('darkMode', true);
|
||||
} catch(err) {
|
||||
this.error("Unable to set the darkMode setting because it isn't named what we expect. WTF?");
|
||||
}
|
||||
} else
|
||||
this.error("Unable to load the Ember settings controller.");
|
||||
var Settings = utils.ember_settings(),
|
||||
ThemeManager = utils.ember_lookup('service:theme-manager');
|
||||
|
||||
if ( ThemeManager ) {
|
||||
ThemeManager.set('themes.activeTheme', 'theme--dark');
|
||||
} else if ( Settings )
|
||||
Settings.set('darkMode', true);
|
||||
|
||||
this._load_dark_css();
|
||||
}
|
||||
|
|
|
@ -10,7 +10,12 @@ var FFZ = window.FrankerFaceZ,
|
|||
FFZ.prototype.fix_tooltips = function() {
|
||||
// Add handlers to FFZ's tooltip classes.
|
||||
jQuery(".html-tooltip").tipsy({live: true, html: true, gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
|
||||
jQuery(".ffz-tooltip").tipsy({live: true, html: true, title: this.render_tooltip(), gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
|
||||
jQuery(".ffz-tooltip").tipsy({
|
||||
live: true,
|
||||
html: true,
|
||||
className: this.render_tooltip_class(),
|
||||
title: this.render_tooltip(),
|
||||
gravity: utils.tooltip_placement(2*constants.TOOLTIP_DISTANCE, 'n')});
|
||||
|
||||
|
||||
// First, override the tooltip mixin.
|
||||
|
|
221
style.css
221
style.css
|
@ -1718,6 +1718,10 @@ body:not(.ffz-bttv) .chat-container:not(.chatReplay) .more-messages-indicator {
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.tipsy-inner .faded {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.ffz-follow-tip .tipsy-inner {
|
||||
width: 316px;
|
||||
}
|
||||
|
@ -1750,6 +1754,218 @@ body:not(.ffz-bttv) .chat-container:not(.chatReplay) .more-messages-indicator {
|
|||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
|
||||
.ffz-rich-tip .tipsy-inner {
|
||||
max-width: 340px;
|
||||
width: 340px;
|
||||
text-align: left;
|
||||
position: relative;
|
||||
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .body { line-height: 1.5em }
|
||||
|
||||
.ffz-rich-tip .tweet-heading:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 24px;
|
||||
right: 24px;
|
||||
width: 20px;
|
||||
height: 16px;
|
||||
background: url("//cdn.frankerfacez.com/script/twitter_sprites.png") -38px -15px;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .stats:after,
|
||||
.ffz-rich-tip .heading:after {
|
||||
content: '';
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .avatar {
|
||||
float: left;
|
||||
margin-right: 8px;
|
||||
height: 48px;
|
||||
width: 48px;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .tweet-heading .avatar {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .display-name {
|
||||
padding-top: 3px;
|
||||
font-size: 14px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .display-name.big-name {
|
||||
font-size: 20px;
|
||||
padding-top: 18px;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .quoted .display-name {
|
||||
padding: 0 5px 0 0;
|
||||
display: inline;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .twitch-heading .badge.verified {
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
margin: 2px 0 -1px 5px;
|
||||
background: url("https://static-cdn.jtvnw.net/badges/v1/d12a2e27-16f6-41d0-ab77-b780518f00a3/1");
|
||||
background-size: contain;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .twitch-heading .big-name .badge.verified {
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
margin: 1px 0 0 10px;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .tweet-heading .badge {
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
margin: 2px 0 -1px 5px;
|
||||
background: url("//cdn.frankerfacez.com/script/twitter_sprites.png");
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .badge.verified {
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .badge.translator {
|
||||
background-position: -12px -15px;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .badge.protected {
|
||||
background-position: -24px -15px;
|
||||
width: 14px;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .emoji {
|
||||
height: 1em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .quoted > div:not(:first-child),
|
||||
.ffz-rich-tip .tipsy-inner > div:not(:first-child) {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .quote-heading + .body,
|
||||
.ffz-rich-tip .replying + .body {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .replying {
|
||||
opacity: 0.6;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .quoted .body,
|
||||
.ffz-rich-tip .stats,
|
||||
.ffz-rich-tip .username { opacity: 0.6 }
|
||||
|
||||
.ffz-rich-tip .stats { display: flex }
|
||||
.ffz-rich-tip time { flex-grow: 1 }
|
||||
|
||||
.ffz-rich-tip .tweet-stats .stat:before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
background: url("//cdn.frankerfacez.com/script/twitter_sprites.png");
|
||||
margin: 0 5px 0 10px;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .stat.likes:before {
|
||||
width: 17px; height: 14px;
|
||||
margin-bottom: -3px;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .stat.retweets:before {
|
||||
width: 20px; height: 12px;
|
||||
background-position: -34px 0;
|
||||
margin-bottom: -2px;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .media { position: relative; text-align: center }
|
||||
|
||||
.ffz-rich-tip .media:not([data-count="1"]) {
|
||||
display: flex;
|
||||
margin: 8px -5px -5px 0;
|
||||
flex-flow: column wrap;
|
||||
height: 329px;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .media video {
|
||||
width: 100%;
|
||||
max-height: 324px;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .media[data-count="4"] { flex-flow: row wrap }
|
||||
|
||||
.ffz-rich-tip .media[data-count="2"] { height: 164.5px }
|
||||
.ffz-rich-tip .media img { max-height: 324px }
|
||||
|
||||
.ffz-rich-tip .quoted .media:not([data-count="1"]) { height: 150px }
|
||||
.ffz-rich-tip .quoted .media[data-count="2"] { height: 150px }
|
||||
.ffz-rich-tip .quoted .media video,
|
||||
.ffz-rich-tip .quoted .media img { max-height: 150px }
|
||||
|
||||
.ffz-rich-tip .media span {
|
||||
background: no-repeat center center;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .media[data-count="2"] span,
|
||||
.ffz-rich-tip .media[data-count="3"] span,
|
||||
.ffz-rich-tip .media[data-count="4"] span {
|
||||
width: calc(50% - 5px);
|
||||
height: calc(50% - 5px);
|
||||
margin: 0 5px 5px 0;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .media[data-count="2"] span,
|
||||
.ffz-rich-tip .media[data-count="3"] span:first-of-type {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .profile-stats {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .profile-stats div {
|
||||
flex-grow: 1;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .profile-stats span {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .quoted {
|
||||
border: 1px solid #474747;
|
||||
border-radius: 5px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.ffz-rich-tip .media[data-type="video"]:after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
width: 64px; height: 64px;
|
||||
top: calc(50% - 32px);
|
||||
left: calc(50% - 32px);
|
||||
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath fill='%23FFF' d='M15 10.001c0 .299-.305.514-.305.514l-8.561 5.303C5.51 16.227 5 15.924 5 15.149V4.852c0-.777.51-1.078 1.135-.67l8.561 5.305c-.001 0 .304.215.304.514z'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
|
||||
/* Menu Page Loader */
|
||||
|
||||
.ffz-ui-sub-menu-page:empty,
|
||||
|
@ -1759,6 +1975,7 @@ body:not(.ffz-bttv) .chat-container:not(.chatReplay) .more-messages-indicator {
|
|||
|
||||
.ffz-loading-spinner:after,
|
||||
.chat-history.loading:after,
|
||||
.ffz-async-tooltip:empty:after,
|
||||
.ffz-ui-sub-menu-page:empty::after,
|
||||
.ffz-ui-menu-page:empty::after {
|
||||
content: " ";
|
||||
|
@ -1772,6 +1989,10 @@ body:not(.ffz-bttv) .chat-container:not(.chatReplay) .more-messages-indicator {
|
|||
animation: ffz-rotateplane 1.2s infinite linear;
|
||||
}
|
||||
|
||||
.ffz-async-tooltip:empty:after {
|
||||
margin: 10px 50px;
|
||||
}
|
||||
|
||||
@keyframes ffz-rotateplane {
|
||||
0% { transform: perspective(120px) rotateY(90deg) }
|
||||
25% { transform: perspective(120px) rotateY(180deg) }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue