From 5fd62c80503b5012ea9bb95329facb4e7a57cc89 Mon Sep 17 00:00:00 2001 From: Jiiks Date: Thu, 8 Mar 2018 13:15:58 +0200 Subject: [PATCH] Move markup cloning to automanipulator --- client/src/builtin/EmoteModule.js | 84 ++----------------- client/src/ui/automanip.js | 69 +++++++++++++++ .../ui/components/common/EditedTimestamp.vue | 8 ++ 3 files changed, 83 insertions(+), 78 deletions(-) create mode 100644 client/src/ui/components/common/EditedTimestamp.vue diff --git a/client/src/builtin/EmoteModule.js b/client/src/builtin/EmoteModule.js index 1e96d5ac..a28484e5 100644 --- a/client/src/builtin/EmoteModule.js +++ b/client/src/builtin/EmoteModule.js @@ -19,89 +19,17 @@ import TwitchEmotes from '../data/twitch_emotes.json'; export default class { static observe() { - Events.on('server-switch', this.injectAll.bind(this)); - Events.on('channel-switch', this.injectAll.bind(this)); - 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 }, - ``, - 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)); + Events.on('mutable:.markup', markup => { + this.injectEmotes(markup); + }); } static injectEmotes(node) { if (!/:[\w]+:/gmi.test(node.textContent)) return node; const childNodes = [...node.childNodes]; 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()) { if (cn.nodeType !== Node.TEXT_NODE) { @@ -152,7 +80,7 @@ export default class { } } } - return newNode; + node.replaceWith(newNode); } static isEmote(word) { diff --git a/client/src/ui/automanip.js b/client/src/ui/automanip.js index f0a71721..2a030ea7 100644 --- a/client/src/ui/automanip.js +++ b/client/src/ui/automanip.js @@ -11,6 +11,8 @@ import { Events, WebpackModules } from 'modules'; import Reflection from './reflection'; import DOM from './dom'; +import VueInjector from './vueinjector'; +import EditedTimeStamp from './components/common/EditedTimeStamp.vue'; class TempApi { static get currentGuildId() { @@ -45,6 +47,7 @@ export default class { this.appMount.setAttribute('guild-id', TempApi.currentGuildId); this.appMount.setAttribute('channel-id', TempApi.currentChannelId); this.setIds(); + this.makeMutable(); } catch (err) { console.log(err); } @@ -54,12 +57,78 @@ export default class { this.appMount.setAttribute('guild-id', TempApi.currentGuildId); this.appMount.setAttribute('channel-id', TempApi.currentChannelId); this.setIds(); + this.makeMutable(); } catch (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 }, + ``, + 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() { for (let msg of document.querySelectorAll('.message')) { if (msg.hasAttribute('message-id')) continue; diff --git a/client/src/ui/components/common/EditedTimestamp.vue b/client/src/ui/components/common/EditedTimestamp.vue new file mode 100644 index 00000000..723cea85 --- /dev/null +++ b/client/src/ui/components/common/EditedTimestamp.vue @@ -0,0 +1,8 @@ + +