Merge pull request #170 from JsSucks/emote-changes-and-minor-stuff

Emote changes and minor stuff
This commit is contained in:
Alexei Stukov 2018-03-15 14:25:12 +02:00 committed by GitHub
commit ae63213809
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 105 additions and 146 deletions

View File

@ -1,6 +1,6 @@
<template> <template>
<span class="bd-emotewrapper" v-tooltip="name"> <span class="bd-emotewrapper" v-tooltip="name">
<img class="bd-emote" :src="src" :alt="name"/> <img class="bd-emote" :src="src" :alt="`;${name};`"/>
</span> </span>
</template> </template>

View File

@ -21,34 +21,34 @@ export default class {
static processMarkup(markup) { static processMarkup(markup) {
if (!emotesEnabled) return markup; // TODO Get it from setttings if (!emotesEnabled) return markup; // TODO Get it from setttings
const newMarkup = []; const newMarkup = [];
for (const [ti, t] of markup.entries()) { for (const child of markup) {
if ('string' !== typeof t) { if ('string' !== typeof child) {
newMarkup.push(t); newMarkup.push(child);
continue; continue;
} }
if (!this.testWord(child)) {
const words = t.split(/([^\s]+)([\s]|$)/g); newMarkup.push(child);
continue;
}
const words = child.split(/([^\s]+)([\s]|$)/g);
if (!words) continue; if (!words) continue;
let text = null; let text = null;
for (const [wi, word] of words.entries()) { for (const [wordIndex, word] of words.entries()) {
let isEmote = false; const isEmote = this.isEmote(word);
if (this.testWord(word)) {
isEmote = true;
}
if (isEmote) { if (isEmote) {
if (text !== null) { if (text !== null) {
newMarkup.push(text); newMarkup.push(text);
text = null; text = null;
} }
newMarkup.push(this.React.createElement('span', { className: 'bd-emote-outer' }, word)); newMarkup.push(this.React.createElement('span', { className: 'bd-emote-outer', 'data-bdemote-name': isEmote.name, 'data-bdemote-src': isEmote.src }));
continue; continue;
} }
if (text === null) { if (text === null) {
text = `${word}`; text = word;
} else { } else {
text += `${word}`; text += word;
} }
if (wi === words.length - 1) { if (wordIndex === words.length - 1) {
newMarkup.push(text); newMarkup.push(text);
} }
} }
@ -57,7 +57,7 @@ export default class {
} }
static testWord(word) { static testWord(word) {
if (!/:[\w]+:/gmi.test(word)) return false; if (!/;[\w]+;/gmi.test(word)) return false;
return true; return true;
} }
@ -84,17 +84,17 @@ export default class {
} }
} }
static injectEmote(e) { static injectEmote(root) {
if (!emotesEnabled) return; if (!emotesEnabled) return;
const isEmote = this.isEmote(e.textContent); const { bdemoteName, bdemoteSrc } = root.dataset;
if (!isEmote) return; if (!bdemoteName || !bdemoteSrc) return;
VueInjector.inject( VueInjector.inject(
e, root,
DOM.createElement('span'), DOM.createElement('span'),
{ EmoteComponent }, { EmoteComponent },
`<EmoteComponent src="${isEmote.src}" name="${isEmote.name}"/>` `<EmoteComponent src="${bdemoteSrc}" name="${bdemoteName}"/>`
); );
e.classList.add('bd-is-emote'); root.classList.add('bd-is-emote');
} }
static injectEmotes(element) { static injectEmotes(element) {
@ -104,7 +104,7 @@ export default class {
static isEmote(word) { static isEmote(word) {
if (!emotes) return null; if (!emotes) return null;
const name = word.replace(/:/g, ''); const name = word.replace(/;/g, '');
const emote = emotes.find(emote => emote.id === name); const emote = emotes.find(emote => emote.id === name);
if (!emote) return null; if (!emote) return null;
let { id, value } = emote; let { id, value } = emote;

View File

@ -1,4 +1,4 @@
import WebpackModules from './webpackmodules'; import { WebpackModules } from './webpackmodules';
import { $ } from 'vendor'; import { $ } from 'vendor';
class List extends Array { class List extends Array {

View File

@ -11,7 +11,7 @@
import EventListener from './eventlistener'; import EventListener from './eventlistener';
import { Utils } from 'common'; import { Utils } from 'common';
import Events from './events'; import Events from './events';
import WebpackModules from './webpackmodules'; import { WebpackModules } from './webpackmodules';
import * as SocketStructs from '../structs/socketstructs'; import * as SocketStructs from '../structs/socketstructs';

View File

@ -6,7 +6,7 @@ export { default as PluginManager } from './pluginmanager';
export { default as ThemeManager } from './thememanager'; export { default as ThemeManager } from './thememanager';
export { default as Globals } from './globals'; export { default as Globals } from './globals';
export { default as Vendor } from './vendor'; export { default as Vendor } from './vendor';
export { default as WebpackModules } from './webpackmodules'; export * from './webpackmodules';
export { default as ModuleManager } from './modulemanager'; export { default as ModuleManager } from './modulemanager';
export { default as EventListener } from './eventlistener'; export { default as EventListener } from './eventlistener';
export { default as SocketProxy } from './socketproxy'; export { default as SocketProxy } from './socketproxy';

View File

@ -8,86 +8,95 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import WebpackModules from './webpackmodules'; import { WebpackModules } from './webpackmodules';
import { ClientLogger as Logger } from 'common';
export default class Patcher { export default class Patcher {
static get patches() { return this._patches || (this._patches = {}) } static get patches() { return this._patches || (this._patches = {}) }
static resolveModule(mn) { static resolveModule(module) {
if (mn instanceof Function || (mn instanceof Object && !(mn instanceof Array))) return mn; if (module instanceof Function || (module instanceof Object && !(module instanceof Array))) return module;
if ('string' === typeof mn) return WebpackModules.getModuleByName(mn); if ('string' === typeof module) return WebpackModules.getModuleByName(module);
if (mn instanceof Array) return WebpackModules.getModuleByProps(mn); if (module instanceof Array) return WebpackModules.getModuleByProps(module);
return null; return null;
} }
static overrideFn(patch) { static overrideFn(patch) {
return function () { return function () {
for (const s of patch.supers) { for (const superPatch of patch.supers) {
try { try {
s.fn.apply(this, arguments); superPatch.callback.apply(this, arguments);
} catch (err) { } } catch (err) {
Logger.err('Patcher', err);
}
} }
const retVal = patch.ofn.apply(this, arguments); const retVal = patch.originalFunction.apply(this, arguments);
for (const s of patch.slaves) { for (const slavePatch of patch.slaves) {
try { try {
s.fn.apply(this, [arguments, { patch, retVal }]); slavePatch.callback.apply(this, [arguments, { patch, retVal }]);
} catch (err) { } } catch (err) {
Logger.err('Patcher', err);
}
} }
return retVal; return retVal;
} }
} }
static rePatch(po) { static rePatch(patch) {
po.patch = po.module[po.fnn] = this.overrideFn(po); patch.proxyFunction = patch.module[patch.functionName] = this.overrideFn(patch);
} }
static pushPatch(id, module, fnn) { static pushPatch(id, module, functionName) {
const patch = { const patch = {
module, module,
fnn, functionName,
ofn: module[fnn], originalFunction: module[functionName],
proxyFunction: null,
revert: () => { revert: () => {
patch.module[patch.fnn] = patch.ofn; patch.module[patch.functionName] = patch.originalFunction;
patch.patch = null; patch.proxyFunction = null;
patch.slaves = patch.supers = []; patch.slaves = patch.supers = [];
}, },
supers: [], supers: [],
slaves: [], slaves: []
patch: null
}; };
patch.patch = module[fnn] = this.overrideFn(patch); patch.proxyFunction = module[functionName] = this.overrideFn(patch);
return this.patches[id] = patch; return this.patches[id] = patch;
} }
static superpatch(mn, fnn, cb, dn) { static superpatch(unresolveModule, functionName, callback, displayName) {
const module = this.resolveModule(mn); const module = this.resolveModule(unresolveModule);
if (!module || !module[fnn] || !(module[fnn] instanceof Function)) return null; if (!module || !module[functionName] || !(module[functionName] instanceof Function)) return null;
const displayName = 'string' === typeof mn ? mn : dn || module.displayName || module.name || module.constructor.displayName || module.constructor.name; displayName = 'string' === typeof unresolveModule ? unresolveModule : displayName || module.displayName || module.name || module.constructor.displayName || module.constructor.name;
const patchId = `${displayName}:${fnn}`; const patchId = `${displayName}:${functionName}`;
const patchObject = this.patches[patchId] || this.pushPatch(patchId, module, fnn);
if (!patchObject.patch) this.rePatch(patchObject); const patch = this.patches[patchId] || this.pushPatch(patchId, module, functionName);
const id = patchObject.supers.length + 1; if (!patch.proxyFunction) this.rePatch(patch);
const patch = { const id = patch.supers.length + 1;
const superPatch = {
id, id,
fn: cb, callback,
unpatch: () => patchObject.supers.splice(patchObject.supers.findIndex(slave => slave.id === id), 1) unpactch: () => patch.slaves.splice(patch.slaves.findIndex(slave => slave.id === id), 1) // This doesn't actually work correctly not, fix in a moment
}; };
patchObject.supers.push(patch);
return patch; patch.supers.push(superPatch);
return superPatch;
} }
static slavepatch(mn, fnn, cb, dn) { static slavepatch(unresolveModule, functionName, callback, displayName) {
const module = this.resolveModule(mn); const module = this.resolveModule(unresolveModule);
if (!module || !module[fnn] || !(module[fnn] instanceof Function)) return null; if (!module || !module[functionName] || !(module[functionName] instanceof Function)) return null;
const displayName = 'string' === typeof mn ? mn : dn || module.displayName || module.name || module.constructor.displayName || module.constructor.name; displayName = 'string' === typeof unresolveModule ? unresolveModule : displayName || module.displayName || module.name || module.constructor.displayName || module.constructor.name;
const patchId = `${displayName}:${fnn}`; const patchId = `${displayName}:${functionName}`;
const patchObject = this.patches[patchId] || this.pushPatch(patchId, module, fnn);
if (!patchObject.patch) this.rePatch(patchObject); const patch = this.patches[patchId] || this.pushPatch(patchId, module, functionName);
const id = patchObject.slaves.length + 1; if (!patch.proxyFunction) this.rePatch(patch);
const patch = { const id = patch.slaves.length + 1;
const slavePatch = {
id, id,
fn: cb, callback,
unpatch: () => patchObject.slaves.splice(patchObject.slaves.findIndex(slave => slave.id === id), 1) unpactch: () => patch.slaves.splice(patch.slaves.findIndex(slave => slave.id === id), 1) // This doesn't actually work correctly not, fix in a moment
}; };
patchObject.slaves.push(patch);
return patch; patch.slaves.push(slavePatch);
return slavePatch;
} }
} }

View File

@ -15,7 +15,7 @@ import PluginManager from './pluginmanager';
import ThemeManager from './thememanager'; import ThemeManager from './thememanager';
import Events from './events'; import Events from './events';
import EventsWrapper from './eventswrapper'; import EventsWrapper from './eventswrapper';
import WebpackModules from './webpackmodules'; import { WebpackModules } from './webpackmodules';
import { SettingsSet, SettingsCategory, Setting, SettingsScheme } from 'structs'; import { SettingsSet, SettingsCategory, Setting, SettingsScheme } from 'structs';
import { BdMenuItems, Modals, DOM, Reflection } from 'ui'; import { BdMenuItems, Modals, DOM, Reflection } from 'ui';
import DiscordApi from './discordapi'; import DiscordApi from './discordapi';

View File

@ -10,40 +10,11 @@
*/ */
import Patcher from './patcher'; import Patcher from './patcher';
import WebpackModules from './webpackmodules'; import { WebpackModules, Filters } from './webpackmodules';
import DiscordApi from './discordapi'; import DiscordApi from './discordapi';
import { EmoteModule } from 'builtin'; import { EmoteModule } from 'builtin';
import { Reflection } from 'ui'; import { Reflection } from 'ui';
class Filters {
static get byPrototypeFields() {
return (fields, selector = x => x) => (module) => {
const component = selector(module);
if (!component) return false;
if (!component.prototype) return false;
for (const field of fields) {
if (!component.prototype[field]) return false;
}
return true;
}
}
static get byCode() {
return (search, selector = x => x) => (module) => {
const method = selector(module);
if (!method) return false;
return method.toString().search(search) !== -1;
}
}
static get and() {
return (...filters) => (module) => {
for (const filter of filters) {
if (!filter(module)) return false;
}
return true;
}
}
}
class Helpers { class Helpers {
static get plannedActions() { static get plannedActions() {
return this._plannedActions || (this._plannedActions = new Map()); return this._plannedActions || (this._plannedActions = new Map());
@ -231,32 +202,6 @@ class ReactComponent {
return this._retVal; return this._retVal;
} }
unpatchRender() {
}
/*
patchRender(actions, updateOthers) {
const self = this;
if (!(actions instanceof Array)) actions = [actions];
Patcher.slavepatch(this.component.prototype, 'render', function (args, obj) {
console.log('obj', obj);
for (const action of actions) {
let { selector, method, fn } = action;
if ('string' === typeof selector) selector = Helpers.parseSelector(selector);
const { item, parent, key } = Helpers.getFirstChild(obj, 'retVal', selector);
console.log('item2', item);
if (!item) continue;
const content = fn.apply(this, [item]);
switch (method) {
case 'replace':
parent[key] = content;
break;
}
}
if (updateOthers) self.forceUpdateOthers();
});
}
*/
forceUpdateOthers() { forceUpdateOthers() {
} }

View File

@ -8,7 +8,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import WebpackModules from './webpackmodules'; import { WebpackModules } from './webpackmodules';
import jQuery from 'jquery'; import jQuery from 'jquery';
import lodash from 'lodash'; import lodash from 'lodash';

View File

@ -8,7 +8,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
class Filters { export class Filters {
static byProperties(props, selector = m => m) { static byProperties(props, selector = m => m) {
return module => { return module => {
const component = selector(module); const component = selector(module);
@ -205,7 +205,7 @@ const KnownModules = {
ExternalLink: Filters.byCode(/\.trusted\b/) ExternalLink: Filters.byCode(/\.trusted\b/)
}; };
export default class WebpackModules { export class WebpackModules {
/** /**
* Finds a module using a filter function. * Finds a module using a filter function.

View File

@ -68,7 +68,8 @@
methods: { methods: {
prevents(e) { prevents(e) {
if (!this.open) return; if (!this.open) return;
if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp' && e.key !== 'Tab') return; if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp' && e.key !== 'Tab' && e.key !== 'Enter') return;
this.traverse(e);
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
}, },
@ -82,38 +83,42 @@
return uri.replace(':id', value); return uri.replace(':id', value);
}, },
searchEmotes(e) { searchEmotes(e) {
if (this.traverse(e)) return; if (e.key === 'ArrowDown' || e.key === 'ArrowUp') return;
if (e.key === 'Tab' && this.open) { if (e.key === 'Tab' || e.key === 'Enter' && this.open) {
const selected = this.emotes[this.selectedIndex]; const selected = this.emotes[this.selectedIndex];
if (!selected) return; if (!selected) return;
this.inject(selected); this.inject(selected);
this.reset(); this.reset();
return; return;
} }
if (e.key === 'Tab' && !this.open) this.open = true;
if (!this.open) return;
const { selectionEnd, value } = e.target; const { selectionEnd, value } = e.target;
this.sterm = value.substr(0, selectionEnd).split(/\s+/g).pop(); this.sterm = value.substr(0, selectionEnd).split(/\s+/g).pop();
if (this.sterm.length < 3) { if (!this.sterm.startsWith(';')) {
this.reset();
return;
}
if (this.sterm.length < 4) {
this.reset(); this.reset();
return; return;
} }
this.title = this.sterm; this.title = this.sterm;
this.emotes = EmoteModule.filter(new RegExp(this.sterm, ''), 10); this.emotes = EmoteModule.filter(new RegExp(this.sterm.substr(1), ''), 10);
this.open = this.emotes.length; this.open = this.emotes.length;
}, },
traverse(e) { traverse(e) {
if (!this.open) return false; if (!this.open) return;
if (e.key === 'ArrowUp') { if (e.key === 'ArrowUp') {
this.selectedIndex = (this.selectedIndex - 1) < 0 ? 9 : this.selectedIndex - 1; this.selectedIndex = (this.selectedIndex - 1) < 0 ? 9 : this.selectedIndex - 1;
return true; return;
} }
if (e.key === 'ArrowDown') { if (e.key === 'ArrowDown') {
this.selectedIndex = (this.selectedIndex + 1) >= 10 ? 0 : this.selectedIndex + 1; this.selectedIndex = (this.selectedIndex + 1) >= 10 ? 0 : this.selectedIndex + 1;
return true; return;
} }
return false; return;
}, },
reset() { reset() {
this.emotes = []; this.emotes = [];
@ -128,7 +133,7 @@
const ta = document.querySelector('.chat textarea'); const ta = document.querySelector('.chat textarea');
if (!ta) return; if (!ta) return;
const { selectionEnd, value } = ta; const { selectionEnd, value } = ta;
const en = `:${emote.id}:`; const en = `;${emote.id};`;
let substr = value.substr(0, selectionEnd); let substr = value.substr(0, selectionEnd);
substr = substr.replace(new RegExp(this.sterm + '$'), en); substr = substr.replace(new RegExp(this.sterm + '$'), en);