Add files

This commit is contained in:
DoomRye 2022-07-26 10:06:20 -07:00
commit bb80829159
18195 changed files with 2122994 additions and 0 deletions

View file

@ -0,0 +1,94 @@
/* @flow */
import ColorGenerator from './config/colors';
export const Colors = {
// Brand
BRAND_PURPLE: '#7289DA',
BRAND_PURPLE_TRANSPARENT: '#7289DA00',
HINT_PURPLE: '#c9d2f0',
DARK_PURPLE: '#697ec4',
// Status
STATUS_RED: '#f04747',
STATUS_GREEN: '#43b581',
STATUS_YELLOW: '#faa61a',
STATUS_GREY: '#747f8d',
// Lights
WHITE: '#ffffff',
WHITE1: '#f9f9f9',
WHITE2: '#f3f3f3',
WHITE3: '#f0f0f0',
WHITE4: '#eceeef',
WHITE5: '#ebebeb',
WHITE6: '#e9e7e7',
WHITE7: '#dbdde1',
WHITE8: '#cdcdcd',
WHITE9: '#737F8D',
PLACEHOLDER: '#dadddf',
PLACEHOLDER2: '#74787d',
MODAL_GREY: '#EFEFF4',
// Darks
BLACK: '#000000',
ORANGE: '#f57731',
GUILDS_GREY: '#1e2124',
CHANNELS_GREY: '#2e3136',
ACCOUNT_GREY: '#282b30',
CHAT_GREY: '#36393e',
UNREAD_GREY: '#8a8e94',
HIGHLIGHT_GREY: '#25282c',
AVATAR_GREY: '#747F8C',
DARK_GREY: '#677179',
GREY1: '#99aab5',
GREY2: '#87909c',
GREY3: '#737f8d',
GREY4: '#949494',
GREY5: '#535559',
GREY6: '#4f545c',
GREY7: '#1c242b',
GREY8: '#575d66',
GREY9: '#202226',
DARK1: '#030303',
LINK: '#00b0f4',
...ColorGenerator()
};
export const Fonts = {
PRIMARY_LIGHT: 'Whitney-Light',
PRIMARY_BOLD: 'Whitney-Bold',
PRIMARY_SEMIBOLD: 'Whitney-Semibold',
PRIMARY_REGULAR: 'Whitney-Book',
PRIMARY: 'Whitney-Medium'
};
export const RECAPTCHA_SITE_KEY = '6Lef5iQTAAAAAKeIvIY-DeexoO3gj7ryl9rLMEnn';
export const OAuth2Scopes = {
IDENTIFY: 'identify',
EMAIL: 'email',
CONNECTIONS: 'connections',
GUILDS: 'guilds',
GUILDS_JOIN: 'guilds.join',
GDM_JOIN: 'gdm.join',
RPC: 'rpc',
RPC_API: 'rpc.api',
RPC_NOTIFICATIONS_READ: 'rpc.notifications.read',
BOT: 'bot',
WEBHOOK_INCOMING: 'webhook.incoming',
MESSAGES_READ: 'messages.read'
};
export default {
Colors,
Fonts,
RECAPTCHA_SITE_KEY,
OAuth2Scopes
};
// WEBPACK FOOTER //
// ./discord_common/js/Constants.js

View file

@ -0,0 +1,83 @@
import React from 'react';
const CLASSNAME = 'file-input';
const STYLE = disabled => ({
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
opacity: 0,
cursor: disabled ? 'not-allowed' : 'pointer'
});
const FileInput = React.createClass({
propTypes: {
onChange: React.PropTypes.func.isRequired,
multiple: React.PropTypes.bool,
filters: React.PropTypes.arrayOf(React.PropTypes.shape({
name: React.PropTypes.string.isRequired,
extensions: React.PropTypes.arrayOf(React.PropTypes.string)
})),
embedded: React.PropTypes.bool,
handleNativeClick: React.PropTypes.func
},
getDefaultProps: function() {
return {
multiple: false,
disabled: false
};
},
activateUploadDialogue() {
if (this.props.embedded) {
this.handleNativeClick();
}
// Not sure if better way?
else if (this._input) {
this._input.click();
}
},
handleNativeClick() {
this.props.handleNativeClick(this.props);
},
handleBrowserInputMouseDown(e) {
e.target.value = null;
},
render() {
const {disabled} = this.props;
// Electron's input[type="file"] does not open on a separate thread and lock's up the app,
// instead use the Electron's custom file dialog.
if (this.props.embedded) {
return <div style={STYLE(disabled)}
className={CLASSNAME}
onClick={!disabled && this.handleNativeClick} />;
}
else {
let accept;
if (this.props.filters) {
accept = this.props.filters.map(filter => filter.extensions.map(ext => `.${ext}`).join(',')).join(',');
}
return <input style={STYLE(disabled)}
className={CLASSNAME}
disabled={disabled}
type="file"
onMouseDown={this.handleBrowserInputMouseDown}
onChange={this.props.onChange}
multiple={this.props.multiple}
accept={accept}
ref={node => this._input = node} />;
}
}
});
export default FileInput;
// WEBPACK FOOTER //
// ./discord_common/js/components/FileInput.js

View file

@ -0,0 +1,28 @@
module.exports = {
PRIMARY: '#4f545c',
BRAND: '#7289DA',
STATUS_RED: '#f04747',
STATUS_YELLOW: '#faa61a',
STATUS_GREEN: '#43b581',
STATUS_GREY: '#747f8d',
LINK: '#00b0f4',
WHITE: '#ffffff',
BLACK: '#000000',
// Other brands
SKYPE: '#009DD7',
BATTLENET: '#009AE5',
STEAM: '#182332',
LOL: '#021F25',
TWITCH: '#593695',
YOUTUBE: '#CB2120',
TWITTER: '#1DA1F2',
REDDIT: '#5F99CF'
};
// WEBPACK FOOTER //
// ./discord_common/js/config/colors/BaseColors.js

View file

@ -0,0 +1,17 @@
module.exports = {
'100': 0.95,
'200': 0.80,
'300': 0.60,
'400': 0.20,
'500': 0,
'600': -0.32,
'630': -0.411,
'700': -0.60,
'800': -0.70,
'900': -0.95
};
// WEBPACK FOOTER //
// ./discord_common/js/config/colors/ColorScales.js

View file

@ -0,0 +1,36 @@
const BaseColors = require('./BaseColors');
const ColorScales = require('./ColorScales');
const ColorFunctions = require('../../utils/ColorFunctions');
const ColorGenerator = (forCSS=false) => {
const Colors = {};
for (const color in BaseColors) {
for (const scale in ColorScales) {
const computedColor = ColorFunctions.lightness(ColorScales[scale], BaseColors[color]);
let colorName;
if (forCSS) {
colorName = color.replace(/_/g, '-').toLowerCase();
Colors[`${colorName}-${scale}`] = computedColor;
}
else {
colorName = color;
Colors[`${colorName}_${scale}`] = computedColor;
}
if (scale === '500') {
Colors[colorName] = computedColor;
}
}
}
return Colors;
};
module.exports = ColorGenerator;
// WEBPACK FOOTER //
// ./discord_common/js/config/colors/index.js

View file

@ -0,0 +1,62 @@
/* @flow */
import React from 'react';
import shallowEqual from '../lib/shallowEqual';
type ReactClass<DefaultProps, Props> = Class<React.Component<DefaultProps, Props, *>>;
interface Store {
addChangeListener(callback: Function): void;
removeChangeListener(callback: Function): void;
}
function getDisplayName(Component: ReactClass): string {
return Component.displayName || Component.name || 'Component';
}
export default function connectStores<DefaultProps, Props, State: Object>(
stores: Array<Store>,
getStateFromStores: (props: Props) => State
): (Component: ReactClass<DefaultProps, Props>) => ReactClass<DefaultProps, $Diff<Props, State>> {
return Component => {
return class extends React.Component<*, *, *> {
static displayName = `FluxContainer(${getDisplayName(Component)})`;
constructor(props) {
super(props);
this.state = getStateFromStores(props);
// $FlowFixMe: Flow does not like rebinding of instance methods.
this._handleStoreChange = this._handleStoreChange.bind(this);
}
_handleStoreChange() {
this.setState(getStateFromStores(this.props));
}
componentWillMount() {
stores.forEach(store => store.addChangeListener(this._handleStoreChange));
}
componentWillReceiveProps(nextProps: Props) {
if (!shallowEqual(this.props, nextProps)) {
this.setState(getStateFromStores(nextProps));
}
}
componentWillUnmount() {
stores.forEach(store => store.removeChangeListener(this._handleStoreChange));
}
render() {
return <Component {...this.props} {...this.state} />;
}
};
};
}
// WEBPACK FOOTER //
// ./discord_common/js/containers/connectStores.js

View file

@ -0,0 +1,199 @@
/* @flow */
import React from 'react';
import classNames from 'classnames';
import {DragSource, DropTarget} from 'react-dnd';
import Styles from './makeDraggable.mod.css';
type Props = {
onHover?: Function,
onDragStart?: Function,
onDragLeave?: Function,
onCancel?: Function,
onDrop?: Function,
children: any,
isOver: boolean,
didDrop: boolean,
connectDropTarget: Function
};
const dragSource = {
beginDrag({dragId}, monitor, component) {
const {onDragStart, onHover, onDrop} = component.context;
onDragStart(dragId);
return {dragId, onDragStart, onHover, onDrop};
},
endDrag(props, monitor) {
const {onDrop} = monitor.getItem();
onDrop(monitor.getDropResult());
}
};
const dropTarget = {
drop({dragId}) {
return {dragId};
},
hover({dragId}, monitor) {
const {onHover} = monitor.getItem();
onHover(dragId);
}
};
function dragCollect(connect, monitor) {
return {
connectDragPreview: connect.dragPreview(),
connectDragSource: connect.dragSource(),
isDragging: monitor.isDragging()
};
}
function dropCollect(connect, _monitor) {
return {
connectDropTarget: connect.dropTarget(),
};
}
export function makeDragItem(TYPE: string) {
// $FlowFixMe - I will need to properly annotate this later
return Component => {
return DropTarget(
TYPE,
dropTarget,
dropCollect
)(DragSource(
TYPE,
dragSource,
dragCollect
)(class extends React.Component {
static draggable = true;
static defaultProps = {
dragClass: ''
};
static contextTypes = {
onHover: React.PropTypes.func,
onDragStart: React.PropTypes.func,
onDrop: React.PropTypes.func,
};
// This is required to not get babel transformed
componentDidMount() {}
render() {
const {
connectDropTarget,
connectDragPreview,
connectDragSource,
isDragging,
dragClass,
...props
} = this.props;
return (
connectDropTarget(
connectDragSource(
<div className={classNames(Styles.draggable, {[dragClass]: isDragging})}>
<Component
isDragging={isDragging}
connectDragPreview={connectDragPreview}
{...props}
/>
</div>
)
)
);
}
}));
};
}
export function makeDragList(TYPE: string) {
// $FlowFixMe - I will need to properly annotate this later
return Component => {
return DropTarget(TYPE, {}, (connect, monitor) => {
return {
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver(),
didDrop: monitor.didDrop()
};
})(class extends React.PureComponent {
props: Props;
_dragging: ?string;
static childContextTypes = {
onHover: React.PropTypes.func,
onDragStart: React.PropTypes.func,
onDrop: React.PropTypes.func,
};
getChildContext() {
return {
onHover: this.handleHover,
onDragStart: this.handleDragStart,
onDrop: this.handleDrop
};
}
componentDidUpdate(prevProps) {
const {onDragLeave, isOver, didDrop} = this.props;
if (
prevProps.isOver !== isOver &&
isOver === false &&
didDrop === false
) {
onDragLeave && onDragLeave();
}
}
constructor(props: Props) {
super(props);
(this: any).handleHover = this.handleHover.bind(this);
(this: any).handleDragStart = this.handleDragStart.bind(this);
(this: any).handleDrop = this.handleDrop.bind(this);
}
handleHover(dragId: string) {
if (dragId === this._dragging) {
return;
}
const {onHover} = this.props;
onHover && onHover(dragId, this._dragging);
}
handleDragStart(dragging: string) {
if (dragging === this._dragging) {
return;
}
this._dragging = dragging;
const {onDragStart} = this.props;
onDragStart && onDragStart(dragging);
}
handleDrop(dropTarget: {dragId: string}) {
this._dragging = null;
const {onCancel, onDrop} = this.props;
if (dropTarget) {
onDrop && onDrop(dropTarget);
}
else {
onCancel && onCancel();
}
}
render() {
const {connectDropTarget, ...props} = this.props;
return connectDropTarget(
<div>
<Component {...props} />
</div>
);
}
});
};
}
// WEBPACK FOOTER //
// ./discord_common/js/containers/makeDraggable.js

View file

@ -0,0 +1,9 @@
// removed by extract-text-webpack-plugin
module.exports = {"draggable":"draggable-2aWBFf"};
//////////////////
// WEBPACK FOOTER
// ./discord_common/js/containers/makeDraggable.mod.css
// module id = 2121
// module chunks = 2

View file

@ -0,0 +1,213 @@
/* @flow */
import lodash from 'lodash';
import moment from 'moment';
import {getMessage} from './parse';
const DEFAULT_LOCALE = 'en-US';
let chosenLocale: string;
let Languages = [];
const Messages = {};
let _getMessages;
let _didSetLocale;
if (__IOS__) {
// $FlowFixMe
require('intl');
}
function findMessages(locale) {
try {
return _getMessages(locale);
}
catch (e) {
console.warn('unsupported locale', locale);
if (locale.indexOf('-') === -1) {
return findMessages(DEFAULT_LOCALE);
}
else {
return findMessages(locale.split('-')[0]);
}
}
}
function loadMessagesForLocale(locale, messagesRecur, prefix) {
const messages = messagesRecur || findMessages(locale);
for (const key in messages) {
const message = messages[key];
if (typeof message == 'object') {
loadMessagesForLocale(locale, message, key);
continue;
}
else if (message.length === 0) {
continue;
}
try {
addToMessages(prefix, key, getMessage(message, locale));
}
catch (e) {
console.warn(`Failed parsing intl key '${key}' in locale '${locale}' defaulting to English`);
}
}
}
function addToMessages(prefix, key, message) {
if (prefix) {
if (Messages[prefix]) {
Messages[prefix][key] = message;
}
else {
Messages[prefix] = {[key]: message};
}
}
else {
Messages[key] = message;
}
}
function setLocale(locale: string) {
if (chosenLocale === locale) return;
const oldLocale = chosenLocale;
chosenLocale = locale;
for (const key of Object.keys(Messages)) {
delete Messages[key];
}
loadMessagesForLocale(DEFAULT_LOCALE);
if (locale !== DEFAULT_LOCALE) {
loadMessagesForLocale(locale);
}
moment.locale([chosenLocale, DEFAULT_LOCALE]);
if (_didSetLocale) {
_didSetLocale(chosenLocale, oldLocale);
}
}
function getSystemLocale(): ?string {
let locale;
if (__IOS__) {
// $FlowFixMe
const localizationManager = require('react-native').NativeModules.LocalizationManager;
if (localizationManager != null) {
locale = localizationManager.Language;
}
}
else {
// $FlowFixMe
const browserChosenLanguage = navigator.languages ? navigator.languages[0] : null;
// $FlowFixMe
locale = browserChosenLanguage || navigator.language || navigator.browserLanguage || navigator.userLanguage;
}
// $FlowFixMe
return locale;
}
function getDefaultLocale() {
let locale = getSystemLocale();
locale = locale || DEFAULT_LOCALE;
const locales = Languages.filter(({enabled}) => enabled).map(({code}) => code);
if (locales.indexOf(locale) !== -1) {
return locale;
}
const [language] = locale.split('-');
if (locales.indexOf(language) !== -1) {
return language;
}
locale = lodash.find(locales, l => {
return l.indexOf('-') && l.split('-')[0] == locale;
});
if (locale) {
return locale;
}
return DEFAULT_LOCALE;
}
function getAvailableLocales() {
const availableLocales = Languages.filter(({enabled}) => enabled).map(({code, name}) => {
return {
value: code,
name,
localizedName: Messages[code] || name
};
});
availableLocales.sort(({name: a}, {name: b}) => {
a = a.toLowerCase();
b = b.toLowerCase();
return a < b ? -1 : a > b ? 1 : 0;
});
return availableLocales;
}
function getLocaleInfo() {
return lodash.find(Languages, lan => lan.code == chosenLocale);
}
type Language = {
name: string,
englishName: string,
code: string,
enabled: boolean
};
type InitOptions = {
initalLocale?: string,
getMessages: (locale: string) => {[key: string]: any},
getLanguages: () => Array<Language>,
didSetLocale: (locale: string) => void
};
function init({initalLocale, getMessages, getLanguages, didSetLocale}: InitOptions) {
// $FlowFixMe
if (Intl.__addLocaleData) {
// $FlowFixMe
Intl.__addLocaleData(require('intl/locale-data/json/en'));
}
_getMessages = getMessages;
Languages = getLanguages();
_didSetLocale = didSetLocale;
setLocale(initalLocale || getDefaultLocale());
}
export type i18nType<Messages: Object> = {
init(options: InitOptions): void,
Messages: {[key: $Keys<Messages>]: any},
getAvailableLocales(): Array<{value: string, name: string, localizedName: string}>,
getLocale(): string,
getLocaleInfo(locale: string): ?Language,
getDefaultLocale(): string,
setLocale(locale: string): void,
getSystemLocale(): ?string,
getLanguages(): Array<Language>,
translationSiteURL: string
};
export default {
init,
Messages: (Messages: any),
getAvailableLocales,
getLocale: () => chosenLocale,
getLocaleInfo,
getDefaultLocale,
setLocale,
getSystemLocale,
getLanguages: () => Languages,
translationSiteURL: 'https://i18n.discordapp.com'
};
// WEBPACK FOOTER //
// ./discord_common/js/i18n/index.js

View file

@ -0,0 +1,142 @@
import IntlMessageFormat from 'intl-messageformat';
import SimpleMarkdown from 'simple-markdown';
const FORMAT_RE = /\{.+?}/;
const MARKDOWN_RE = /[~*_]{2}.+?[~*_]{2}|\[.+?]\(.+?\)|\n\n/;
const UNSAFE_RE = /!!/;
const UNSAFE_RE_ALL = /!!/g;
let updateRules = rules => rules;
if (__IOS__) {
updateRules = require('./updateRules.ios');
}
else if (__WEB__ && !__SDK__) {
updateRules = require('./updateRules.web');
}
function parserFor(rules) {
const parser = SimpleMarkdown.parserFor(updateRules(rules));
const output = SimpleMarkdown.reactFor(SimpleMarkdown.ruleOutput(rules, 'react'));
return function(str, context, unsafeContext) {
const inline = str.indexOf('\n\n') === -1;
if (!inline) {
str += '\n\n';
}
return output(parser(str, {inline, context, unsafeContext}));
};
}
function parserForNonReact(rules) {
const parser = SimpleMarkdown.parserFor(rules);
return function(str, context, unsafeContext) {
return parser(str + '\n\n', {inline: false, context, unsafeContext});
};
}
const linkRule = SimpleMarkdown.defaultRules.link;
const rules = {
newline: SimpleMarkdown.defaultRules.newline,
paragraph: SimpleMarkdown.defaultRules.paragraph,
url: SimpleMarkdown.defaultRules.url,
link: {
...linkRule,
parse(capture, parse, state) {
const node = linkRule.parse(capture, parse, state);
node.context = state.context;
return node;
}
},
strong: SimpleMarkdown.defaultRules.strong,
u: SimpleMarkdown.defaultRules.u,
br: SimpleMarkdown.defaultRules.br,
em: SimpleMarkdown.defaultRules.em,
hook: {
order: SimpleMarkdown.defaultRules.text.order,
match: SimpleMarkdown.inlineRegex(/^\$\[(.*?)\]\((\w+)\)/),
parse(capture, parse, state) {
const {context} = state;
return {
render: context[capture[2]],
content: parse(capture[1], state)
};
},
react(node, output, state) {
return node.render(output(node.content, state), state.key);
}
},
noparse: {
order: SimpleMarkdown.defaultRules.text.order,
match: SimpleMarkdown.inlineRegex(/^!!(\d+?)!!/),
parse(capture, parse, {unsafeContext}) {
return {
type: 'text',
content: unsafeContext[capture[1]]
};
},
react(node) {
return node.content;
}
},
text: SimpleMarkdown.defaultRules.text
};
const parse = parserFor(rules);
const parseForNonReact = parserForNonReact(rules);
function getMessage(str, locale) {
if (str == null) {
return str;
}
str = str.replace(/^\n+|\n+$/g, '');
const hasMarkdown = MARKDOWN_RE.test(str);
if (FORMAT_RE.test(str) || hasMarkdown) {
if (!hasMarkdown) {
str = str.replace(UNSAFE_RE_ALL, '');
}
const intlMessage = new IntlMessageFormat(str, locale);
if (hasMarkdown) {
const originalFormat = intlMessage.format;
const unsafe = UNSAFE_RE.test(str);
intlMessage.format = (context={}, react=true) => {
const unsafeContext = {};
if (unsafe) {
let i = 0;
for (const key of Object.keys(context)) {
const value = context[key];
if (typeof value === 'string') {
unsafeContext[++i] = value;
context[key] = i;
}
}
}
if (!react) {
return parseForNonReact(originalFormat(context), context, unsafeContext);
}
return parse(originalFormat(context), context, unsafeContext);
};
intlMessage.plainFormat = originalFormat;
}
return intlMessage;
}
return str;
}
export default {
getMessage
};
// WEBPACK FOOTER //
// ./discord_common/js/i18n/parse.js

View file

@ -0,0 +1,36 @@
import React from 'react';
import SimpleMarkdown from 'simple-markdown';
export default function updateRules(rules) {
rules.paragraph.react = (node, output, state) => {
return <p key={state.key}>{output(node.content, state)}</p>;
};
rules.link.react = (node, output, state) => {
const props = {};
if (node.context != null) {
const handlers = node.context[node.target];
if (handlers && handlers.onClick) {
props.onClick = handlers.onClick;
props.onContextMenu = handlers.onContextMenu;
}
else {
props.onClick = handlers;
}
}
if (props.onClick == null) {
props.href = SimpleMarkdown.sanitizeUrl(node.target);
props.target = '_blank';
}
return <a key={state.key} title={node.title} {...props}>{output(node.content, state)}</a>;
};
return rules;
}
// WEBPACK FOOTER //
// ./discord_common/js/i18n/updateRules.web.js

View file

@ -0,0 +1,91 @@
import {EventEmitter} from 'events';
const THRESHOLD = 160;
const INTERVAL = 500;
const ORIENTATIONS = {
VERTICAL: 'vertical',
HORIZONTAL: 'horizontal'
};
let devTools = {
open: false,
orientation: null
};
function hasFirebug() {
try {
return window.Firebug.chrome.isInitialized;
}
catch (e) {
return false;
}
}
function widthDifference() {
try {
return window.outerWidth - window.innerWidth;
}
catch (e) {
return 0;
}
}
function heightDifference() {
try {
return window.outerHeight - window.innerHeight;
}
catch (e) {
return 0;
}
}
class DevToolsListener extends EventEmitter {
constructor() {
super();
setInterval(() => this.check(), INTERVAL);
}
get orientations() {
return Object.values(ORIENTATIONS);
}
get state() {
return devTools;
}
check() {
const widthThreshold = widthDifference() > THRESHOLD;
const heightThreshold = heightDifference() > THRESHOLD;
const orientation = widthThreshold ? ORIENTATIONS.VERTICAL : ORIENTATIONS.HORIZONTAL;
if (
!(heightThreshold && widthThreshold) &&
(hasFirebug() || widthThreshold || heightThreshold)
) {
const open = devTools.open;
devTools = {
open: true,
orientation
};
if (!open || devTools.orientation !== orientation) {
this.emit('changed', devTools);
}
}
else if (devTools.open) {
devTools.open = false;
this.emit('changed', devTools);
}
}
}
export default DevToolsListener;
// WEBPACK FOOTER //
// ./discord_common/js/lib/DevToolsListener.js

View file

@ -0,0 +1,23 @@
export function consoleWarning(messages) {
console.log(
`%c${messages.SELF_XSS_HEADER}`,
'color: #7289DA; -webkit-text-stroke: 2px black; font-size: 72px; font-weight: bold;'
);
console.log(
`%c${messages.SELF_XSS_LINE_1}`,
'font-size: 16px;'
);
console.log(
`%c${messages.SELF_XSS_LINE_2}`,
'font-size: 18px; font-weight: bold; color: red;'
);
console.log(
`%c${messages.SELF_XSS_LINE_3}`,
'font-size: 16px;'
);
}
// WEBPACK FOOTER //
// ./discord_common/js/lib/XSSDefenses.js

View file

@ -0,0 +1,29 @@
/**
* Shallow compare to objects with the option to ignore certain keys.
*/
export default function shallowEqual(a: Object, b: Object, ignore: Array<string>): boolean {
if (a === b) {
return true;
}
const keysA = Object.keys(a);
const keysB = Object.keys(b);
if (keysA.length !== keysB.length) {
return false;
}
for (let i = 0; i < keysA.length; i++) {
const key = keysA[i];
if (a[key] !== b[key] && (ignore == null || ignore.indexOf(key) === -1)) {
return false;
}
}
return true;
}
// WEBPACK FOOTER //
// ./discord_common/js/lib/shallowEqual.js

View file

@ -0,0 +1,75 @@
/* eslint-disable */
function percentToFraction(amount) {
if (typeof amount === 'string' && amount.indexOf('%') !== -1) {
amount = parseInt(amount, 10) / 100;
}
return amount;
}
const sbcRip = d => {
const l = d.length;
const RGB = new Object();
const i = parseInt;
if (l > 9) {
d = d.split(',');
if (d.length < 3 || d.length > 4) return null; //ErrorCheck
RGB[0] = i(d[0].slice(4)), RGB[1] = i(d[1]), RGB[2] = i(d[2]), RGB[3] = d[3] ? parseFloat(d[3]) : -1;
}
else {
if (l == 8 || l == 6 || l < 4) return null; //ErrorCheck
if (l < 6) d = '#' + d[1] + d[1] + d[2] + d[2] + d[3] + d[3] + (l > 4 ? d[4] + '' + d[4] : ''); //3 digit
d = i(d.slice(1), 16), RGB[0] = d >> 16 & 255, RGB[1] = d >> 8 & 255, RGB[2] = d & 255, RGB[3] = l == 9 || l == 5 ? r(((d >> 24 & 255) / 255) * 10000) / 10000 : -1;
}
return RGB;
};
function lightness(p, from, to) {
if (
typeof(p) != 'number' ||
p < -1 ||
p > 1 ||
typeof(from) != 'string' ||
(from[0] != 'r' && from[0] != '#') ||
(typeof(to) != 'string' &&
typeof(to) != 'undefined')
) {
return null; //ErrorCheck
}
let i = parseInt;
let r = Math.round;
let hh = from.length > 9;
let h = typeof(to) == 'string' ? to.length > 9 ? true : to == 'c' ? !hh : false : hh;
let b = p < 0;
p = b ? p * -1 : p;
to = to && to != 'c' ? to : b ? '#000000' : '#FFFFFF';
let f = sbcRip(from);
let t = sbcRip(to);
if (!f || !t) {
return null; //ErrorCheck
}
if (h) {
return 'rgb(' + r((t[0] - f[0]) * p + f[0]) + ',' + r((t[1] - f[1]) * p + f[1]) + ',' + r((t[2] - f[2]) * p + f[2]) + (f[3] < 0 && t[3] < 0 ? ')' : ',' + (f[3] > -1 && t[3] > -1 ? r(((t[3] - f[3]) * p + f[3]) * 10000) / 10000 : t[3] < 0 ? f[3] : t[3]) + ')');
}
return '#' + (0x100000000 + (f[3] > -1 && t[3] > -1 ? r(((t[3] - f[3]) * p + f[3]) * 255) : t[3] > -1 ? r(t[3] * 255) : f[3] > -1 ? r(f[3] * 255) : 255) * 0x1000000 + r((t[0] - f[0]) * p + f[0]) * 0x10000 + r((t[1] - f[1]) * p + f[1]) * 0x100 + r((t[2] - f[2]) * p + f[2])).toString(16).slice(f[3] > -1 || t[3] > -1 ? 1 : 3);
}
module.exports = {
darken: function(color, amount) {
return lightness(-(percentToFraction(amount)), color);
},
lighten: function(color, amount) {
return lightness(percentToFraction(amount), color);
},
lightness
};
// WEBPACK FOOTER //
// ./discord_common/js/utils/ColorFunctions.js

View file

@ -0,0 +1,90 @@
/* @flow */
const HEX_REGEX = /^#?([a-f,A-F,0-9]{1,2})([a-f,A-F,0-9]{1,2})([a-f,A-F,0-9]{1,2})$/;
function pad2(s: string): string {
return s.length == 1 ? `0${s}` : s;
}
export function hex2int(hex: string): ?number {
if (!hex) return;
// #FFF style
if (hex.length === 4) {
hex = `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}`;
}
return parseInt(hex.slice(1), 16);
}
export function int2hex(colorInt: number): string {
const r = (colorInt >> 16) & 0xff;
const g = (colorInt >> 8) & 0xff;
const b = colorInt & 0xff;
return `#${pad2(r.toString(16))}${pad2(g.toString(16))}${pad2(b.toString(16))}`;
}
export function hex2rgb(hex: string, alpha?: number=1): ?string {
let match = hex.match(HEX_REGEX);
if (match) {
match = match.slice(1);
if (match.length !== 3) {
return null;
}
const rgb = match.map(value => {
if (value.length === 1) {
value += value;
}
return parseInt(value, 16);
});
return `rgba(${rgb.join(', ')}, ${alpha})`;
}
return null;
}
export function rgb2hex(rgb: string): ?string {
const match = rgb.match(/\d{1,3}/g);
if (match && match.length >= 3) {
const [r, g, b, a] = match.slice(1);
if (a == null || a == '0') {
return 'transparent';
}
return `#${pad2(r.toString(16))}${pad2(g.toString(16))}${pad2(b.toString(16))}`;
}
return null;
}
export function int2rgba(colorInt: number, alpha: ?number): string {
if (alpha == null) {
alpha = ((colorInt >> 24) & 0xff) / 255;
}
const r = (colorInt >> 16) & 0xff;
const g = (colorInt >> 8) & 0xff;
const b = colorInt & 0xff;
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
}
export function getDarkness(color: number) {
const r = color >> 16 & 0xFF;
const g = color >> 8 & 0xFF;
const b = color & 0xFF;
return 1 - (0.299 * r + 0.587 * g + 0.114 * b) / 255;
}
export function isValidHex(hex: string): boolean {
if (hex.length !== 4 && hex.length != 7 || hex[0] != '#') {
return false;
}
return hex.match(HEX_REGEX) != null;
}
// WEBPACK FOOTER //
// ./discord_common/js/utils/ColorUtils.js