2018-03-08 09:40:29 +01:00
|
|
|
/**
|
|
|
|
* BetterDiscord Automated DOM Manipulations
|
|
|
|
* Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks
|
|
|
|
* All rights reserved.
|
|
|
|
* https://betterdiscord.net
|
|
|
|
*
|
|
|
|
* This source code is licensed under the MIT license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree.
|
|
|
|
*/
|
|
|
|
|
|
|
|
import { Events, WebpackModules } from 'modules';
|
|
|
|
import Reflection from './reflection';
|
|
|
|
import DOM from './dom';
|
2018-03-08 12:15:58 +01:00
|
|
|
import VueInjector from './vueinjector';
|
|
|
|
import EditedTimeStamp from './components/common/EditedTimeStamp.vue';
|
2018-03-08 09:40:29 +01:00
|
|
|
|
|
|
|
class TempApi {
|
|
|
|
static get currentGuildId() {
|
|
|
|
try {
|
|
|
|
return WebpackModules.getModuleByName('SelectedGuildStore').getGuildId();
|
|
|
|
} catch (err) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static get currentChannelId() {
|
|
|
|
try {
|
|
|
|
return WebpackModules.getModuleByName('SelectedChannelStore').getChannelId();
|
|
|
|
} catch (err) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static get currentUserId() {
|
|
|
|
try {
|
|
|
|
return WebpackModules.getModuleByName('UserStore').getCurrentUser().id;
|
|
|
|
} catch (err) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default class {
|
|
|
|
|
|
|
|
constructor() {
|
2018-03-08 09:59:51 +01:00
|
|
|
window.Reflection = Reflection;
|
2018-03-08 09:40:29 +01:00
|
|
|
Events.on('server-switch', e => {
|
|
|
|
try {
|
|
|
|
this.appMount.setAttribute('guild-id', TempApi.currentGuildId);
|
|
|
|
this.appMount.setAttribute('channel-id', TempApi.currentChannelId);
|
|
|
|
this.setIds();
|
2018-03-08 12:15:58 +01:00
|
|
|
this.makeMutable();
|
2018-03-08 09:40:29 +01:00
|
|
|
} catch (err) {
|
|
|
|
console.log(err);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
Events.on('channel-switch', e => {
|
|
|
|
try {
|
|
|
|
this.appMount.setAttribute('guild-id', TempApi.currentGuildId);
|
|
|
|
this.appMount.setAttribute('channel-id', TempApi.currentChannelId);
|
|
|
|
this.setIds();
|
2018-03-08 12:15:58 +01:00
|
|
|
this.makeMutable();
|
2018-03-08 09:40:29 +01:00
|
|
|
} catch (err) {
|
|
|
|
console.log(err);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-03-08 12:15:58 +01:00
|
|
|
getEts(node) {
|
|
|
|
try {
|
|
|
|
const reh = Object.keys(node).find(k => k.startsWith('__reactInternalInstance'));
|
|
|
|
return node[reh].memoizedProps.children[node[reh].memoizedProps.children.length - 1].props.text;
|
|
|
|
} catch (err) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
makeMutable() {
|
|
|
|
for (const el of document.querySelectorAll('.markup:not(.mutable)')) {
|
|
|
|
this.injectMarkup(el, this.cloneMarkup(el), false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cloneMarkup(node) {
|
|
|
|
const childNodes = [...node.childNodes];
|
|
|
|
const clone = document.createElement('div');
|
|
|
|
clone.className = 'markup mutable';
|
|
|
|
const ets = this.getEts(node);
|
|
|
|
for (const [cni, cn] of childNodes.entries()) {
|
|
|
|
if (cn.nodeType !== Node.TEXT_NODE) {
|
|
|
|
if (cn.className.includes('edited')) continue;
|
|
|
|
}
|
|
|
|
clone.appendChild(cn.cloneNode(true));
|
|
|
|
}
|
|
|
|
return { clone, ets }
|
|
|
|
}
|
|
|
|
|
|
|
|
injectMarkup(sibling, markup, reinject) {
|
|
|
|
if (sibling.className && sibling.className.includes('mutable')) return; // Ignore trying to make mutable again
|
|
|
|
let cc = null;
|
|
|
|
for (const cn of sibling.parentElement.childNodes) {
|
|
|
|
if (cn.className && cn.className.includes('mutable')) cc = cn;
|
|
|
|
}
|
|
|
|
if (cc) sibling.parentElement.removeChild(cc);
|
|
|
|
if (markup === true) markup = this.cloneMarkup(sibling);
|
|
|
|
|
|
|
|
sibling.parentElement.insertBefore(markup.clone, sibling);
|
|
|
|
sibling.classList.add('shadow');
|
|
|
|
sibling.style.display = 'none';
|
|
|
|
if (markup.ets) {
|
|
|
|
const etsRoot = document.createElement('span');
|
|
|
|
markup.clone.appendChild(etsRoot);
|
|
|
|
VueInjector.inject(
|
|
|
|
etsRoot,
|
|
|
|
DOM.createElement('span', null, 'test'),
|
|
|
|
{ EditedTimeStamp },
|
|
|
|
`<EditedTimeStamp ets="${markup.ets}"/>`,
|
|
|
|
true
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2018-03-08 13:04:51 +01:00
|
|
|
Events.emit('ui:mutable:.markup', markup.clone);
|
2018-03-08 12:15:58 +01:00
|
|
|
|
|
|
|
if (reinject) return;
|
|
|
|
new MutationObserver(() => {
|
|
|
|
this.injectMarkup(sibling, this.cloneMarkup(sibling), true);
|
|
|
|
}).observe(sibling, { characterData: false, attributes: false, childList: true, subtree: false });
|
|
|
|
|
|
|
|
new MutationObserver(() => {
|
|
|
|
this.injectMarkup(sibling, this.cloneMarkup(sibling), true);
|
|
|
|
}).observe(sibling, { characterData: true, attributes: false, childList: false, subtree: true });
|
|
|
|
}
|
|
|
|
|
2018-03-08 09:40:29 +01:00
|
|
|
setIds() {
|
|
|
|
for (let msg of document.querySelectorAll('.message')) {
|
|
|
|
if (msg.hasAttribute('message-id')) continue;
|
2018-03-08 09:59:51 +01:00
|
|
|
const r = Reflection(msg);
|
|
|
|
const message = r.prop('message');
|
2018-03-08 09:40:29 +01:00
|
|
|
if (!message) continue;
|
|
|
|
const { id, author } = message;
|
|
|
|
if (!id || !author) continue;
|
|
|
|
const currentUser = author.id === TempApi.currentUserId;
|
|
|
|
DOM.setAttributes(msg, [{ name: 'message-id', value: message.id }]);
|
|
|
|
const msgGroup = msg.closest('.message-group');
|
|
|
|
if (!msgGroup) continue;
|
|
|
|
DOM.setAttributes(msgGroup, [{ name: 'author-id', value: author.id }, { name: 'author-is-currentuser', value: currentUser }]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
get appMount() {
|
|
|
|
return document.getElementById('app-mount');
|
|
|
|
}
|
|
|
|
}
|