Move markup cloning to automanipulator
This commit is contained in:
parent
8bda3e9b4d
commit
5fd62c8050
|
@ -19,89 +19,17 @@ import TwitchEmotes from '../data/twitch_emotes.json';
|
||||||
export default class {
|
export default class {
|
||||||
|
|
||||||
static observe() {
|
static observe() {
|
||||||
Events.on('server-switch', this.injectAll.bind(this));
|
Events.on('mutable:.markup', markup => {
|
||||||
Events.on('channel-switch', this.injectAll.bind(this));
|
this.injectEmotes(markup);
|
||||||
Events.on('discord:MESSAGE_CREATE', e => {
|
});
|
||||||
// Assume that it's the last one for now since the event doesn't give the element
|
|
||||||
const query = document.querySelectorAll('.markup:not(.mutable)');
|
|
||||||
if (!query) return;
|
|
||||||
this.injectMarkup(query[query.length - 1], true);
|
|
||||||
}); // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
static injectAll() {
|
|
||||||
for (const el of document.querySelectorAll('.markup:not(.mutable)')) {
|
|
||||||
this.injectMarkup(el, this.cloneMarkup(el), false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static 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 }
|
|
||||||
}
|
|
||||||
|
|
||||||
static 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static injectMarkup(sibling, markup, reinject) {
|
|
||||||
if (sibling.className && sibling.className.includes('mutable')) return; // Ignore trying to make mutable 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);
|
|
||||||
markup.clone = this.injectEmotes(markup.clone);
|
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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 });
|
|
||||||
}
|
|
||||||
|
|
||||||
static makeMutable(node) {
|
|
||||||
if (node.classList && node.classList.contains('shadow')) return;
|
|
||||||
this.injectMarkup(node, this.cloneMarkup(node));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static injectEmotes(node) {
|
static injectEmotes(node) {
|
||||||
if (!/:[\w]+:/gmi.test(node.textContent)) return node;
|
if (!/:[\w]+:/gmi.test(node.textContent)) return node;
|
||||||
const childNodes = [...node.childNodes];
|
const childNodes = [...node.childNodes];
|
||||||
const newNode = document.createElement('div');
|
const newNode = document.createElement('div');
|
||||||
newNode.className = 'markup mutable hasEmotes';
|
newNode.className = node.className;
|
||||||
|
newNode.classList.add('hasEmotes');
|
||||||
|
|
||||||
for (const [cni, cn] of childNodes.entries()) {
|
for (const [cni, cn] of childNodes.entries()) {
|
||||||
if (cn.nodeType !== Node.TEXT_NODE) {
|
if (cn.nodeType !== Node.TEXT_NODE) {
|
||||||
|
@ -152,7 +80,7 @@ export default class {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return newNode;
|
node.replaceWith(newNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static isEmote(word) {
|
static isEmote(word) {
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
import { Events, WebpackModules } from 'modules';
|
import { Events, WebpackModules } from 'modules';
|
||||||
import Reflection from './reflection';
|
import Reflection from './reflection';
|
||||||
import DOM from './dom';
|
import DOM from './dom';
|
||||||
|
import VueInjector from './vueinjector';
|
||||||
|
import EditedTimeStamp from './components/common/EditedTimeStamp.vue';
|
||||||
|
|
||||||
class TempApi {
|
class TempApi {
|
||||||
static get currentGuildId() {
|
static get currentGuildId() {
|
||||||
|
@ -45,6 +47,7 @@ export default class {
|
||||||
this.appMount.setAttribute('guild-id', TempApi.currentGuildId);
|
this.appMount.setAttribute('guild-id', TempApi.currentGuildId);
|
||||||
this.appMount.setAttribute('channel-id', TempApi.currentChannelId);
|
this.appMount.setAttribute('channel-id', TempApi.currentChannelId);
|
||||||
this.setIds();
|
this.setIds();
|
||||||
|
this.makeMutable();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
|
@ -54,12 +57,78 @@ export default class {
|
||||||
this.appMount.setAttribute('guild-id', TempApi.currentGuildId);
|
this.appMount.setAttribute('guild-id', TempApi.currentGuildId);
|
||||||
this.appMount.setAttribute('channel-id', TempApi.currentChannelId);
|
this.appMount.setAttribute('channel-id', TempApi.currentChannelId);
|
||||||
this.setIds();
|
this.setIds();
|
||||||
|
this.makeMutable();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Events.emit('mutable:.markup', markup.clone);
|
||||||
|
|
||||||
|
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 });
|
||||||
|
}
|
||||||
|
|
||||||
setIds() {
|
setIds() {
|
||||||
for (let msg of document.querySelectorAll('.message')) {
|
for (let msg of document.querySelectorAll('.message')) {
|
||||||
if (msg.hasAttribute('message-id')) continue;
|
if (msg.hasAttribute('message-id')) continue;
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
<template>
|
||||||
|
<span class="edited" v-tooltip="ets">(edited)</span>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: ['ets']
|
||||||
|
}
|
||||||
|
</script>
|
Loading…
Reference in New Issue