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>
<span class="bd-emotewrapper" v-tooltip="name">
<img class="bd-emote" :src="src" :alt="name"/>
<img class="bd-emote" :src="src" :alt="`;${name};`"/>
</span>
</template>

View File

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

View File

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

View File

@ -11,7 +11,7 @@
import EventListener from './eventlistener';
import { Utils } from 'common';
import Events from './events';
import WebpackModules from './webpackmodules';
import { WebpackModules } from './webpackmodules';
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 Globals } from './globals';
export { default as Vendor } from './vendor';
export { default as WebpackModules } from './webpackmodules';
export * from './webpackmodules';
export { default as ModuleManager } from './modulemanager';
export { default as EventListener } from './eventlistener';
export { default as SocketProxy } from './socketproxy';

View File

@ -8,86 +8,95 @@
* 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 {
static get patches() { return this._patches || (this._patches = {}) }
static resolveModule(mn) {
if (mn instanceof Function || (mn instanceof Object && !(mn instanceof Array))) return mn;
if ('string' === typeof mn) return WebpackModules.getModuleByName(mn);
if (mn instanceof Array) return WebpackModules.getModuleByProps(mn);
static resolveModule(module) {
if (module instanceof Function || (module instanceof Object && !(module instanceof Array))) return module;
if ('string' === typeof module) return WebpackModules.getModuleByName(module);
if (module instanceof Array) return WebpackModules.getModuleByProps(module);
return null;
}
static overrideFn(patch) {
return function () {
for (const s of patch.supers) {
for (const superPatch of patch.supers) {
try {
s.fn.apply(this, arguments);
} catch (err) { }
superPatch.callback.apply(this, arguments);
} catch (err) {
Logger.err('Patcher', err);
}
}
const retVal = patch.ofn.apply(this, arguments);
for (const s of patch.slaves) {
const retVal = patch.originalFunction.apply(this, arguments);
for (const slavePatch of patch.slaves) {
try {
s.fn.apply(this, [arguments, { patch, retVal }]);
} catch (err) { }
slavePatch.callback.apply(this, [arguments, { patch, retVal }]);
} catch (err) {
Logger.err('Patcher', err);
}
}
return retVal;
}
}
static rePatch(po) {
po.patch = po.module[po.fnn] = this.overrideFn(po);
static rePatch(patch) {
patch.proxyFunction = patch.module[patch.functionName] = this.overrideFn(patch);
}
static pushPatch(id, module, fnn) {
static pushPatch(id, module, functionName) {
const patch = {
module,
fnn,
ofn: module[fnn],
functionName,
originalFunction: module[functionName],
proxyFunction: null,
revert: () => {
patch.module[patch.fnn] = patch.ofn;
patch.patch = null;
patch.module[patch.functionName] = patch.originalFunction;
patch.proxyFunction = null;
patch.slaves = patch.supers = [];
},
supers: [],
slaves: [],
patch: null
slaves: []
};
patch.patch = module[fnn] = this.overrideFn(patch);
patch.proxyFunction = module[functionName] = this.overrideFn(patch);
return this.patches[id] = patch;
}
static superpatch(mn, fnn, cb, dn) {
const module = this.resolveModule(mn);
if (!module || !module[fnn] || !(module[fnn] instanceof Function)) return null;
const displayName = 'string' === typeof mn ? mn : dn || module.displayName || module.name || module.constructor.displayName || module.constructor.name;
const patchId = `${displayName}:${fnn}`;
const patchObject = this.patches[patchId] || this.pushPatch(patchId, module, fnn);
if (!patchObject.patch) this.rePatch(patchObject);
const id = patchObject.supers.length + 1;
const patch = {
static superpatch(unresolveModule, functionName, callback, displayName) {
const module = this.resolveModule(unresolveModule);
if (!module || !module[functionName] || !(module[functionName] instanceof Function)) return null;
displayName = 'string' === typeof unresolveModule ? unresolveModule : displayName || module.displayName || module.name || module.constructor.displayName || module.constructor.name;
const patchId = `${displayName}:${functionName}`;
const patch = this.patches[patchId] || this.pushPatch(patchId, module, functionName);
if (!patch.proxyFunction) this.rePatch(patch);
const id = patch.supers.length + 1;
const superPatch = {
id,
fn: cb,
unpatch: () => patchObject.supers.splice(patchObject.supers.findIndex(slave => slave.id === id), 1)
callback,
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) {
const module = this.resolveModule(mn);
if (!module || !module[fnn] || !(module[fnn] instanceof Function)) return null;
const displayName = 'string' === typeof mn ? mn : dn || module.displayName || module.name || module.constructor.displayName || module.constructor.name;
const patchId = `${displayName}:${fnn}`;
const patchObject = this.patches[patchId] || this.pushPatch(patchId, module, fnn);
if (!patchObject.patch) this.rePatch(patchObject);
const id = patchObject.slaves.length + 1;
const patch = {
static slavepatch(unresolveModule, functionName, callback, displayName) {
const module = this.resolveModule(unresolveModule);
if (!module || !module[functionName] || !(module[functionName] instanceof Function)) return null;
displayName = 'string' === typeof unresolveModule ? unresolveModule : displayName || module.displayName || module.name || module.constructor.displayName || module.constructor.name;
const patchId = `${displayName}:${functionName}`;
const patch = this.patches[patchId] || this.pushPatch(patchId, module, functionName);
if (!patch.proxyFunction) this.rePatch(patch);
const id = patch.slaves.length + 1;
const slavePatch = {
id,
fn: cb,
unpatch: () => patchObject.slaves.splice(patchObject.slaves.findIndex(slave => slave.id === id), 1)
callback,
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 Events from './events';
import EventsWrapper from './eventswrapper';
import WebpackModules from './webpackmodules';
import { WebpackModules } from './webpackmodules';
import { SettingsSet, SettingsCategory, Setting, SettingsScheme } from 'structs';
import { BdMenuItems, Modals, DOM, Reflection } from 'ui';
import DiscordApi from './discordapi';

View File

@ -10,40 +10,11 @@
*/
import Patcher from './patcher';
import WebpackModules from './webpackmodules';
import { WebpackModules, Filters } from './webpackmodules';
import DiscordApi from './discordapi';
import { EmoteModule } from 'builtin';
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 {
static get plannedActions() {
return this._plannedActions || (this._plannedActions = new Map());
@ -231,32 +202,6 @@ class ReactComponent {
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() {
}

View File

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

View File

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

View File

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