1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-06-28 05:15:54 +00:00
FrankerFaceZ/src/utils.js

471 lines
14 KiB
JavaScript
Raw Normal View History

var FFZ = window.FrankerFaceZ,
constants = require('./constants');
var sanitize_el = document.createElement('span'),
sanitize = function(msg) {
sanitize_el.textContent = msg;
return sanitize_el.innerHTML;
},
escape_regex = RegExp.escape || function(str) {
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
},
R_QUOTE = /"/g,
R_SQUOTE = /'/g,
R_AMP = /&/g,
R_LT = /</g,
R_GT = />/g,
DURATIONS = {},
quote_attr = function(msg) {
return msg.replace(R_AMP, "&amp;").replace(R_QUOTE, "&quot;").replace(R_SQUOTE, "&apos;").replace(R_LT, "&lt;").replace(R_GT, "&gt;");
},
HUMAN_NUMBERS = [
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"
],
number_commas = function(x) {
var parts = x.toString().split(".");
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
return parts.join(".");
},
2015-06-10 18:46:04 -04:00
pluralize = function(value, singular, plural) {
plural = plural || 's';
singular = singular || '';
return value === 1 ? singular : plural;
},
place_string = function(num) {
if ( num == 1 ) return '1st';
else if ( num == 2 ) return '2nd';
else if ( num == 3 ) return '3rd';
else if ( num == null ) return '---';
return num + "th";
},
date_regex = /^(\d{4}|\+\d{6})(?:-?(\d{2})(?:-?(\d{2})(?:T(\d{2})(?::?(\d{2})(?::?(\d{2})(?:(?:\.|,)(\d{1,}))?)?)?(Z|([\-+])(\d{2})(?::?(\d{2}))?)?)?)?)?$/,
parse_date = function(str) {
if ( typeof str === "number" )
return new Date(str);
var parts = str.match(date_regex);
if ( ! parts )
return null;
2015-06-10 18:46:04 -04:00
parts[7] = (parts[7] && parts[7].length) ? parts[7].substr(0, 3) : 0;
var unix = Date.UTC(parts[1], parts[2] - 1, parts[3], parts[4], parts[5], parts[6], parts[7]);
// Check Offset
if ( parts[9] ) {
var offset = (parts[9] == "-" ? 1 : -1) * 60000 * (60*parts[10] + 1*parts[11]);
unix += offset;
}
return new Date(unix);
2015-07-04 17:06:36 -04:00
},
uncompressEmotes = function(value) {
var output = {},
emotes = value.split("/"),
i = emotes.length;
while(i--) {
var parts = emotes[i].split(":");
if ( parts.length !== 3 )
return {};
var emote_id = parts[0],
length = parseInt(parts[1]),
positions = parts[2].split(","),
indices = output[emote_id] = output[emote_id] || [];
for(var j=0, jl = positions.length; j < jl; j++) {
var start = parseInt(positions[j]),
end = start + length;
for(var x=0, xl = indices.length; x < xl; x++) {
if ( start < indices[x][0] )
break;
}
indices.splice(x, 0, [start, end]);
}
}
return output;
},
2015-07-04 17:06:36 -04:00
// This code borrowed from the twemoji project, with tweaks.
UFE0Fg = /\uFE0F/g,
U200D = String.fromCharCode(0x200D),
2015-07-04 17:06:36 -04:00
EMOJI_CODEPOINTS = {},
emoji_to_codepoint = function(surrogates, sep) {
if ( EMOJI_CODEPOINTS[surrogates] && EMOJI_CODEPOINTS[surrogates][sep] )
return EMOJI_CODEPOINTS[surrogates][sep];
var input = surrogates.indexOf(U200D) === -1 ? surrogates.replace(UFE0Fg, '') : surrogates,
out = [],
c = 0, p = 0, i = 0;
while (i < input.length) {
c = input.charCodeAt(i++);
if ( p ) {
out.push((0x10000 + ((p - 0xD800) << 10) + (c - 0xDC00)).toString(16));
p = 0;
} else if ( 0xD800 <= c && c <= 0xDBFF )
p = c;
else
out.push(c.toString(16));
}
var retval = EMOJI_CODEPOINTS[surrogates] = out.join('-');
return retval;
},
2015-07-04 17:06:36 -04:00
codepoint_to_emoji = function(codepoint) {
var code = typeof codepoint === 'string' ? parseInt(codepoint, 16) : codepoint;
if ( code < 0x10000 )
return String.fromCharCode(code);
code -= 0x10000;
return String.fromCharCode(
0xD800 + (code >> 10),
0xDC00 + (code & 0x3FF)
)
},
2015-07-04 17:06:36 -04:00
// Twitch Emote Helpers
SRCSETS = {},
build_srcset = function(id) {
if ( SRCSETS[id] )
return SRCSETS[id];
var out = SRCSETS[id] = constants.TWITCH_BASE + id + "/1.0 1x, " + constants.TWITCH_BASE + id + "/2.0 2x";
return out;
},
// Twitch API
api_call = function(method, url, data, options, token) {
options = options || {};
var headers = options.headers = options.headers || {};
headers['Client-ID'] = constants.CLIENT_ID;
if ( token )
headers.Authorization = 'OAuth ' + token;
return Twitch.api[method].call(this, url, data, options);
},
// Dialogs
show_modal = function(contents, on_close, width) {
var container = document.createElement('div'),
subwindow = document.createElement('div'),
card = document.createElement('div'),
close_button = document.createElement('div'),
closer = function() { container.parentElement.removeChild(container) };
container.className = 'twitch_subwindow_container';
container.id = 'ffz-modal-container';
subwindow.className = 'twitch_subwindow ffz-subwindow';
subwindow.style.width = '100%';
subwindow.style.maxWidth = (width||420) + 'px';
card.className = 'card';
close_button.className = 'modal-close-button';
close_button.innerHTML = constants.CLOSE;
close_button.addEventListener('click', function() {
closer();
if ( on_close )
on_close(false);
});
container.appendChild(subwindow);
subwindow.appendChild(card);
subwindow.appendChild(close_button);
card.appendChild(contents);
var el = document.querySelector('app-main');
if ( el )
el.parentElement.insertBefore(container, el.nextSibling);
else
document.body.appendChild(container);
return closer;
},
ember_lookup = function(thing) {
if ( ! window.App )
return;
if ( App.__deprecatedInstance__ && App.__deprecatedInstance__.registry && App.__deprecatedInstance__.registry.lookup )
return App.__deprecatedInstance__.registry.lookup(thing);
if ( App.__container__ && App.__container__.lookup )
return App.__container__.lookup(thing);
};
module.exports = FFZ.utils = {
ember_views: function() {
return ember_lookup('-view-registry:main') || {};
},
ember_lookup: ember_lookup,
ember_resolve: function(thing) {
if ( ! window.App )
return;
if ( App.__deprecatedInstance__ && App.__deprecatedInstance__.registry && App.__deprecatedInstance__.registry.resolve )
return App.__deprecatedInstance__.registry.resolve(thing);
if ( App.__container__ && App.__container__.resolve )
return App.__container__.resolve(thing);
},
build_srcset: build_srcset,
/*build_tooltip: build_tooltip,
load_emote_data: load_emote_data,*/
api: {
del: function(u,d,o,t) { return api_call('del', u,d,o,t); },
get: function(u,d,o,t) { return api_call('get', u,d,o,t); },
post: function(u,d,o,t) { return api_call('post', u,d,o,t); },
put: function(u,d,o,t) { return api_call('put', u,d,o,t); }
},
show_modal: show_modal,
prompt: function(title, description, old_value, callback, width) {
var contents = document.createElement('div'),
heading = document.createElement('div'),
form = document.createElement('form'),
input, close_btn, okay_btn;
contents.className = 'text-content';
heading.className = 'content-header';
heading.innerHTML = '<h4>' + title + '</h4>';
form.innerHTML = '<div class="item">' + (description ? '<p>' + description + '</p>' : '') + '<input type="text"></div><div class="buttons"><a class="js-subwindow-close button"><span>Cancel</span></a><button class="button primary" type="submit"><span>OK</span></button></div>';
contents.appendChild(heading);
contents.appendChild(form);
input = form.querySelector('input');
close_btn = form.querySelector('.js-subwindow-close');
okay_btn = form.querySelector('.button.primary');
if ( old_value !== undefined )
input.value = old_value;
var closer,
cb = function(success) {
closer();
if ( ! callback )
return;
callback(success ? input.value : null);
};
closer = show_modal(contents, cb, width);
form.addEventListener('submit', function(e) { e.preventDefault(); cb(true); return false });
okay_btn.addEventListener('click', function(e) { e.preventDefault(); cb(true); return false });
close_btn.addEventListener('click', function(e) { e.preventDefault(); cb(false); return false });
},
last_minute: function() {
var now = new Date();
if ( now.getSeconds() >= 30 )
now.setMinutes(now.getMinutes()+1);
now.setSeconds(0);
now.setMilliseconds(0);
return now.getTime();
},
maybe_chart: function(series, point, render, force) {
var len = series.data.length;
if ( force || point.y !== null || (len > 0 && series.data[len-1].y !== null) ) {
series.addPoint(point, render);
return true;
}
return false;
},
update_css: function(element, id, css) {
var all = element.innerHTML,
start = "/*BEGIN " + id + "*/",
end = "/*END " + id + "*/",
s_ind = all.indexOf(start),
e_ind = all.indexOf(end),
found = s_ind !== -1 && e_ind !== -1 && e_ind > s_ind;
if ( !found && !css )
return;
if ( found )
all = all.substr(0, s_ind) + all.substr(e_ind + end.length);
if ( css )
all += start + css + end;
element.innerHTML = all;
},
2015-07-04 17:06:36 -04:00
tooltip_placement: function(margin, prefer) {
return function() {
var pref = prefer;
if ( typeof pref === "function" )
pref = pref.call(this);
var dir = {ns: pref[0], ew: (pref.length > 1 ? pref[1] : false)},
$this = $(this),
half_width = $this.width() / 2,
half_height = $this.height() / 2,
boundTop = $(document).scrollTop() + half_height + (margin*2),
boundLeft = $(document).scrollLeft() + half_width + margin;
if ($this.offset().top < boundTop) dir.ns = 'n';
if ($this.offset().left < boundLeft) dir.ew = 'w';
if ($(window).width() + $(document).scrollLeft() - ($this.offset().left + half_width) < margin) dir.ew = 'e';
if ($(window).height() + $(document).scrollTop() - ($this.offset().top + half_height) < (2*margin)) dir.ns = 's';
return dir.ns + (dir.ew ? dir.ew : '');
}
},
uncompressEmotes: uncompressEmotes,
2015-07-04 17:06:36 -04:00
emoji_to_codepoint: emoji_to_codepoint,
codepoint_to_emoji: codepoint_to_emoji,
2015-07-04 17:06:36 -04:00
parse_date: parse_date,
number_commas: number_commas,
place_string: place_string,
placement: function(entrant) {
if ( entrant.state == "forfeit" ) return "Forfeit";
else if ( entrant.state == "dq" ) return "DQed";
else if ( entrant.place ) return place_string(entrant.place);
return "";
},
sanitize: sanitize,
quote_attr: quote_attr,
date_string: function(date) {
return date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate();
},
2015-06-10 18:46:04 -04:00
pluralize: pluralize,
human_number: function(value) {
return HUMAN_NUMBERS[value] || number_commas(value);
},
human_time: function(elapsed, factor) {
factor = factor || 1;
2015-06-10 18:46:04 -04:00
elapsed = Math.floor(elapsed);
var years = Math.floor((elapsed*factor) / 31536000) / factor;
if ( years >= 1 )
2015-06-10 18:46:04 -04:00
return years + ' year' + pluralize(years);
var days = Math.floor((elapsed %= 31536000) / 86400);
if ( days >= 1 )
2015-06-10 18:46:04 -04:00
return days + ' day' + pluralize(days);
var hours = Math.floor((elapsed %= 86400) / 3600);
if ( hours >= 1 )
2015-06-10 18:46:04 -04:00
return hours + ' hour' + pluralize(hours);
var minutes = Math.floor((elapsed %= 3600) / 60);
if ( minutes >= 1 )
2015-06-10 18:46:04 -04:00
return minutes + ' minute' + pluralize(minutes);
var seconds = elapsed % 60;
if ( seconds >= 1 )
2015-06-10 18:46:04 -04:00
return seconds + ' second' + pluralize(seconds);
return 'less than a second';
},
time_to_string: function(elapsed, separate_days, days_only, no_hours, no_seconds) {
var seconds = elapsed % 60,
minutes = Math.floor(elapsed / 60),
hours = Math.floor(minutes / 60),
days = null;
minutes = minutes % 60;
if ( separate_days ) {
days = Math.floor(hours / 24);
hours = hours % 24;
if ( days_only && days > 0 )
return days + " days";
days = ( days > 0 ) ? days + " days, " : "";
}
return (days||'') + ((!no_hours || days || hours) ? ((days && hours < 10 ? "0" : "") + hours + ':') : '') + (minutes < 10 ? "0" : "") + minutes + (no_seconds ? "" : (":" + (seconds < 10 ? "0" : "") + seconds));
},
duration_string: function(val) {
if ( val === 1 )
return 'Purge';
if ( DURATIONS[val] )
return DURATIONS[val];
var weeks, days, hours, minutes, seconds;
weeks = Math.floor(val / 604800);
seconds = val % 604800;
days = Math.floor(seconds / 86400);
seconds %= 86400;
hours = Math.floor(seconds / 3600);
seconds %= 3600;
minutes = Math.floor(seconds / 60);
seconds %= 60;
var out = DURATIONS[val] = (weeks ? weeks + 'w' : '') + ((days || (weeks && (hours || minutes || seconds))) ? days + 'd' : '') + ((hours || ((weeks || days) && (minutes || seconds))) ? hours + 'h' : '') + ((minutes || ((weeks || days || hours) && seconds)) ? minutes + 'm' : '') + (seconds ? seconds + 's' : '');
return out;
},
format_unread: function(count) {
if ( count < 1 )
return "";
else if ( count >= 99 )
return "99+";
return "" + count;
},
escape_regex: escape_regex
}