From 6fbe24b6f8758d7bb5d4081bc4f7b2c7b32b3c9e Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Wed, 11 Dec 2019 16:53:04 +0800 Subject: [PATCH] feat: inject KnownIdentity into twitter profile page close #469 --- .../twitter.com/ui/inject.tsx | 2 + .../twitter.com/ui/injectKnownIdentity.tsx | 63 +++++++++++++++++++ .../twitter.com/utils/selector.ts | 18 ++++-- 3 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 src/social-network-provider/twitter.com/ui/injectKnownIdentity.tsx diff --git a/src/social-network-provider/twitter.com/ui/inject.tsx b/src/social-network-provider/twitter.com/ui/inject.tsx index 7c2416fa567..b5b04c0369d 100644 --- a/src/social-network-provider/twitter.com/ui/inject.tsx +++ b/src/social-network-provider/twitter.com/ui/inject.tsx @@ -5,6 +5,7 @@ import { hasDraftEditor, newPostEditorBelow, postPopupInjectPointSelector } from import { renderInShadowRoot } from '../../../utils/jss/renderInShadowRoot' import { PostInfo, SocialNetworkUIInjections } from '../../../social-network/ui' import { injectPostInspectorDefault } from '../../../social-network/defaults/injectPostInspector' +import { injectKnownIdentityAtTwitter } from './injectKnownIdentity' // Closing these shadowRoot prevents external access to them. const newMOW = (i: LiveSelector) => @@ -34,4 +35,5 @@ const injectPostInspector = (current: PostInfo) => { export const twitterUIInjections: SocialNetworkUIInjections = { injectPostBox, injectPostInspector, + injectKnownIdentity: injectKnownIdentityAtTwitter, } diff --git a/src/social-network-provider/twitter.com/ui/injectKnownIdentity.tsx b/src/social-network-provider/twitter.com/ui/injectKnownIdentity.tsx new file mode 100644 index 00000000000..8be3f0bc922 --- /dev/null +++ b/src/social-network-provider/twitter.com/ui/injectKnownIdentity.tsx @@ -0,0 +1,63 @@ +import { MutationObserverWatcher } from '@holoflows/kit' +import { PersonKnown } from '../../../components/InjectedComponents/PersonKnown' +import { bioSelector, bioCard } from '../utils/selector' +import { renderInShadowRoot } from '../../../utils/jss/renderInShadowRoot' +import { PersonIdentifier } from '../../../database/type' +import { twitterUrl } from '../utils/url' +import { makeStyles } from '@material-ui/styles' +import { timeout } from '../../../utils/utils' +import AsyncComponent from '../../../utils/components/AsyncComponent' +import { useState } from 'react' +import { bioCardParser } from '../utils/fetch' + +const useStyles = makeStyles({ + root: { + marginTop: -10, + marginBottom: 10, + }, + center: { + color: '#657786', // TODO: use color in theme + justifyContent: 'flex-start', + marginBottom: 0, + }, +}) + +function PersonKnownAtTwitter() { + const [userId, setUserId] = useState(PersonIdentifier.unknown.userId) + return ( + { + const [bioCardNode] = await timeout(new MutationObserverWatcher(bioCard(false)), 10000) + setUserId(bioCardParser(bioCardNode).handle) + }} + dependencies={[userId]} + awaitingComponent={null} + completeComponent={ + + } + failedComponent={null} + /> + ) +} + +export function injectKnownIdentityAtTwitter() { + const target = new MutationObserverWatcher(bioSelector()) + .setDOMProxyOption({ + beforeShadowRootInit: { mode: 'closed' }, + afterShadowRootInit: { mode: 'closed' }, + }) + .startWatch({ + childList: true, + subtree: true, + characterData: true, + }) + + renderInShadowRoot(, target.firstDOMProxy.beforeShadow) +} diff --git a/src/social-network-provider/twitter.com/utils/selector.ts b/src/social-network-provider/twitter.com/utils/selector.ts index 5d0035b6f96..2700ace7dcb 100644 --- a/src/social-network-provider/twitter.com/utils/selector.ts +++ b/src/social-network-provider/twitter.com/utils/selector.ts @@ -4,20 +4,27 @@ import { postBoxInPopup } from './postBox' import { isNull } from 'lodash-es' type E = HTMLElement -const querySelector = (selector: string) => { - return new LiveSelector().querySelector(selector).enableSingleMode() +const querySelector = ( + selector: string, + singleMode: boolean = true, +) => { + const ls = new LiveSelector().querySelector(selector) + return (singleMode ? ls.enableSingleMode() : ls) as LiveSelector } const querySelectorAll = (selector: string) => { return new LiveSelector().querySelectorAll(selector) } -export const bioCard = () => - querySelector( +export const bioSelector = () => querySelector(['[data-testid="UserProfileHeader_Items"]'].join()) + +export const bioCard = (singleMode = true) => + querySelector( [ '.profile', // legacy twitter 'a[href*="header_photo"] ~ div', // new twitter 'div[data-testid="primaryColumn"] > div > div:last-child > div > div > div > div ~ div', // new twitter without header photo ].join(), + singleMode, ) export const newPostButton = () => querySelector('[data-testid="SideNav_NewTweet_Button"]') @@ -25,8 +32,7 @@ export const newPostButton = () => querySelector('[data-testid="SideNav_NewTw const postEditor = () => postBoxInPopup() ? '[aria-labelledby="modal-header"]' : '[role="main"] :not(aside) > [role="progressbar"] ~ div' -export const newPostEditorBelow: () => LiveSelector = () => - querySelector('[role="main"] :not(aside) > [role="progressbar"] ~ div') +export const newPostEditorBelow = () => querySelector('[role="main"] :not(aside) > [role="progressbar"] ~ div') export const newPostEditorSelector = () => querySelector(`${postEditor()} .DraftEditor-root`) export const newPostEditorFocusAnchor = () => querySelector(`${postEditor()} .public-DraftEditor-content`)