mirror of
https://github.com/insin/control-panel-for-twitter.git
synced 2025-06-18 14:45:31 -04:00
- Added checkSocialContext to TimelineOptions instead of hardcoding it for profile timelines
- Fixed Community Tweets being treated as Retweets - Fixed handling timelines in Communities tabs - Replaced hardcoding of the primary column selector Options: - Fixed options textarea styles - Fixed background in macOS Safari options popup in dark mode - Apply other settings changes after options input changes
This commit is contained in:
parent
331f79215b
commit
b3076019c8
23
options.css
23
options.css
@ -129,7 +129,6 @@ section.group > label {
|
||||
|
||||
section.group > section > * {
|
||||
color: rgb(95, 99, 104);
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
p {
|
||||
@ -148,12 +147,19 @@ section.group > section > p {
|
||||
|
||||
section.textarea {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 4px 12px 4px 0;
|
||||
margin: 8px 0;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
section.textarea > textarea {
|
||||
margin: 8px 12px 12px 0;
|
||||
}
|
||||
|
||||
section.textarea > button {
|
||||
margin: 0 12px 12px 0;
|
||||
}
|
||||
|
||||
section.textarea > p {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
section.textarea button {
|
||||
@ -162,7 +168,9 @@ section.textarea button {
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
/* Prevent zooming */
|
||||
body.iOS.safari textarea {
|
||||
font-size: 16px;
|
||||
@ -498,6 +506,9 @@ body.iOS.safari .checkbox input:focus + .toggle {
|
||||
}
|
||||
|
||||
/* Safari dark mode overrides */
|
||||
body.macOS.safari {
|
||||
background-color: transparent;
|
||||
}
|
||||
body.macOS.safari p {
|
||||
color: rgb(184, 184, 184) !important;
|
||||
}
|
||||
|
27
options.js
27
options.js
@ -186,6 +186,7 @@ const defaultConfig = {
|
||||
// Default based on the platform if the main script hasn't run on Twitter yet
|
||||
version: /(Android|iP(ad|hone))/.test(navigator.userAgent) ? 'mobile' : 'desktop',
|
||||
}
|
||||
//#endregion
|
||||
|
||||
//#region Config & variables
|
||||
/**
|
||||
@ -290,15 +291,18 @@ function onFormChanged(/** @type {Event} */ e) {
|
||||
if (e.target instanceof HTMLTextAreaElement) return
|
||||
|
||||
/** @type {import("./types").StoredConfig} */
|
||||
let changedConfig = {}
|
||||
let changedConfig = Object.create(null)
|
||||
/** @type {Partial<import("./types").UserSettings>} */
|
||||
let changedSettings = {}
|
||||
let changedSettings = Object.create(null)
|
||||
|
||||
// Handle input
|
||||
let $el = /** @type {HTMLInputElement} */ (e.target)
|
||||
if ($el.type == 'checkbox') {
|
||||
// All internal config is currently checkbox toggles
|
||||
if (INTERNAL_CONFIG_FORM_KEYSET.has($el.name)) {
|
||||
config[$el.name] = changedConfig[$el.name] = $el.checked
|
||||
}
|
||||
// Checkbox group toggle
|
||||
else if (checkboxGroups.has($el.name)) {
|
||||
checkboxGroups.get($el.name).forEach(checkboxName => {
|
||||
config.settings[checkboxName] = changedSettings[checkboxName] = $el.checked
|
||||
@ -306,24 +310,23 @@ function onFormChanged(/** @type {Event} */ e) {
|
||||
})
|
||||
$el.indeterminate = false
|
||||
}
|
||||
// Individual checkbox toggle
|
||||
else {
|
||||
// Individual checkbox change
|
||||
config.settings[$el.name] = changedSettings[$el.name] = $el.checked
|
||||
|
||||
// Don't try to redirect the Home timeline to Notifications if both are disabled
|
||||
if ($el.name == 'hideNotifications' &&
|
||||
$el.checked &&
|
||||
config.settings.disabledHomeTimelineRedirect == 'notifications') {
|
||||
let key = 'disabledHomeTimelineRedirect'
|
||||
$form.elements[key].value = config.settings[key] = changedSettings[key] = 'messages'
|
||||
}
|
||||
|
||||
updateCheckboxGroups()
|
||||
}
|
||||
} else {
|
||||
config.settings[$el.name] = changedSettings[$el.name] = $el.value
|
||||
}
|
||||
|
||||
// Apply other settings changes based on input
|
||||
// Don't try to redirect the Home timeline to Notifications if both are disabled
|
||||
if (changedSettings.hideNotifications &&
|
||||
config.settings.disabledHomeTimelineRedirect == 'notifications') {
|
||||
let key = 'disabledHomeTimelineRedirect'
|
||||
$form.elements[key].value = config.settings[key] = changedSettings[key] = 'messages'
|
||||
}
|
||||
|
||||
updateDisplay()
|
||||
if (Object.keys(changedSettings).length > 0) {
|
||||
changedConfig.settings = changedSettings
|
||||
|
102
script.js
102
script.js
@ -2701,7 +2701,7 @@ async function observeDesktopComposeTweetModal($popup) {
|
||||
* tab and re-added when you navigate to another Home timeline tab.
|
||||
*/
|
||||
async function observeDesktopHomeTimelineTweetBox() {
|
||||
let $container = await getElement('div[data-testid="primaryColumn"] > div', {
|
||||
let $container = await getElement(`${Selectors.PRIMARY_COLUMN} > div`, {
|
||||
name: 'Home timeline Tweet box container',
|
||||
stopIf: pageIsNot(currentPage),
|
||||
})
|
||||
@ -4903,10 +4903,11 @@ function getTweetType($tweet, checkSocialContext = false) {
|
||||
if ($tweet.closest(Selectors.PROMOTED_TWEET_CONTAINER)) {
|
||||
return 'PROMOTED_TWEET'
|
||||
}
|
||||
// Assume social context tweets are Retweets
|
||||
if ($tweet.querySelector('[data-testid="socialContext"]')) {
|
||||
// Assume social context tweets are Retweets if we're not checking
|
||||
if (checkSocialContext) {
|
||||
let svgPath = $tweet.querySelector('svg path')?.getAttribute('d') ?? ''
|
||||
if (svgPath.startsWith('M7.471 21H.472l.029-1.027c.184')) return 'COMMUNITY_TWEET'
|
||||
if (svgPath.startsWith('M7 4.5C7 3.12 8.12 2 9.5 2h5C1')) return 'PINNED_TWEET'
|
||||
}
|
||||
// Quoted tweets from accounts you blocked or muted are displayed as an
|
||||
@ -5542,7 +5543,12 @@ function onPopup($popup) {
|
||||
*/
|
||||
function onTimelineChange($timeline, page, seen, options = {}) {
|
||||
let startTime = Date.now()
|
||||
let {classifyTweets = true, hideHeadings = true, isUserTimeline = false} = options
|
||||
let {
|
||||
checkSocialContext = false,
|
||||
classifyTweets = true,
|
||||
hideHeadings = true,
|
||||
isUserTimeline = false
|
||||
} = options
|
||||
|
||||
let isOnHomeTimeline = isOnHomeTimelinePage()
|
||||
let isOnListTimeline = isOnListPage()
|
||||
@ -5587,7 +5593,7 @@ function onTimelineChange($timeline, page, seen, options = {}) {
|
||||
let isBlueTweet = false
|
||||
|
||||
if ($tweet != null) {
|
||||
itemType = getTweetType($tweet, isOnProfileTimeline)
|
||||
itemType = getTweetType($tweet, checkSocialContext)
|
||||
if (timelineHasSpecificHandling) {
|
||||
isReply = isReplyToPreviousTweet($tweet)
|
||||
if (isReply && hidPreviousItem != null) {
|
||||
@ -5654,7 +5660,7 @@ function onTimelineChange($timeline, page, seen, options = {}) {
|
||||
}
|
||||
|
||||
if (!timelineHasSpecificHandling) {
|
||||
if (itemType != null) {
|
||||
if (!hideItem && itemType != null) {
|
||||
hideItem = shouldHideOtherTimelineItem(itemType)
|
||||
}
|
||||
}
|
||||
@ -5797,21 +5803,27 @@ function onTitleChange(title) {
|
||||
)
|
||||
|
||||
if (newPage == currentPage) {
|
||||
log(`ignoring duplicate title change`)
|
||||
// Navigation within the Compose Tweet modal triggers duplcate title changes
|
||||
if (isDesktopComposeTweetModalOpen) {
|
||||
if (currentPath == ModalPaths.COMPOSE_TWEET && COMPOSE_TWEET_MODAL_PAGES.has(location.pathname)) {
|
||||
log('navigated away from Compose Tweet editor')
|
||||
disconnectObservers(modalObservers, 'modal')
|
||||
}
|
||||
else if (COMPOSE_TWEET_MODAL_PAGES.has(currentPath) && location.pathname == ModalPaths.COMPOSE_TWEET) {
|
||||
log('navigated back to Compose Tweet editor')
|
||||
observeDesktopComposeTweetModal($desktopComposeTweetModalPopup)
|
||||
if (isOnCommunitiesPage() &&
|
||||
URL_COMMUNITIES_RE.test(location.pathname) &&
|
||||
currentPath != location.pathname) {
|
||||
log('navigated between Communities tabs (no title change)')
|
||||
} else {
|
||||
log(`ignoring duplicate title change`)
|
||||
// Navigation within the Compose Tweet modal triggers duplcate title changes
|
||||
if (isDesktopComposeTweetModalOpen) {
|
||||
if (currentPath == ModalPaths.COMPOSE_TWEET && COMPOSE_TWEET_MODAL_PAGES.has(location.pathname)) {
|
||||
log('navigated away from Compose Tweet editor')
|
||||
disconnectObservers(modalObservers, 'modal')
|
||||
}
|
||||
else if (COMPOSE_TWEET_MODAL_PAGES.has(currentPath) && location.pathname == ModalPaths.COMPOSE_TWEET) {
|
||||
log('navigated back to Compose Tweet editor')
|
||||
observeDesktopComposeTweetModal($desktopComposeTweetModalPopup)
|
||||
}
|
||||
}
|
||||
currentNotificationCount = notificationCount
|
||||
currentPath = location.pathname
|
||||
return
|
||||
}
|
||||
currentNotificationCount = notificationCount
|
||||
currentPath = location.pathname
|
||||
return
|
||||
}
|
||||
|
||||
// Search terms are shown in the title
|
||||
@ -6242,6 +6254,8 @@ function shouldHideListTimelineItem(type) {
|
||||
*/
|
||||
function shouldHideOtherTimelineItem(type) {
|
||||
switch (type) {
|
||||
case 'COMMUNITY_TWEET':
|
||||
case 'PINNED_TWEET':
|
||||
case 'QUOTE_TWEET':
|
||||
case 'RETWEET':
|
||||
case 'RETWEETED_QUOTE_TWEET':
|
||||
@ -6295,23 +6309,26 @@ async function tweakBookmarksPage() {
|
||||
}
|
||||
|
||||
function tweakCommunitiesPage() {
|
||||
observeTimeline(currentPage)
|
||||
observeTimeline(currentPage, {
|
||||
checkSocialContext: true,
|
||||
isTabbed: true,
|
||||
tabbedTimelineContainerSelector: `${Selectors.PRIMARY_COLUMN} > div > div:last-child`,
|
||||
})
|
||||
}
|
||||
|
||||
function tweakCommunityPage() {
|
||||
if (settings.premiumBlueChecks != 'ignore') {
|
||||
observeTimeline(currentPage, {
|
||||
classifyTweets: false,
|
||||
isTabbed: true,
|
||||
tabbedTimelineContainerSelector: `${Selectors.PRIMARY_COLUMN} > div > div:last-child`,
|
||||
onTimelineAppeared() {
|
||||
// The About tab has static content at the top which can include a check
|
||||
if (/\/about\/?$/.test(location.pathname)) {
|
||||
processBlueChecks(document.querySelector(Selectors.PRIMARY_COLUMN))
|
||||
}
|
||||
observeTimeline(currentPage, {
|
||||
checkSocialContext: true,
|
||||
hideHeadings: false,
|
||||
isTabbed: true,
|
||||
tabbedTimelineContainerSelector: `${Selectors.PRIMARY_COLUMN} > div > div:last-child`,
|
||||
onTimelineAppeared() {
|
||||
// The About tab has static content at the top which can include a check
|
||||
if (/\/about\/?$/.test(location.pathname)) {
|
||||
processBlueChecks(document.querySelector(Selectors.PRIMARY_COLUMN))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function tweakCommunityMembersPage() {
|
||||
@ -6319,7 +6336,7 @@ function tweakCommunityMembersPage() {
|
||||
observeTimeline(currentPage, {
|
||||
classifyTweets: false,
|
||||
isTabbed: true,
|
||||
timelineSelector: 'div[data-testid="primaryColumn"] > div > div:last-child',
|
||||
timelineSelector: `${Selectors.PRIMARY_COLUMN} > div > div:last-child`,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -6383,7 +6400,7 @@ async function tweakExplorePage() {
|
||||
observeTimeline(currentPage, {
|
||||
classifyTweets: false,
|
||||
isTabbed: true,
|
||||
tabbedTimelineContainerSelector: 'div[data-testid="primaryColumn"] > div > div:last-child > div',
|
||||
tabbedTimelineContainerSelector: `${Selectors.PRIMARY_COLUMN} > div > div:last-child > div`,
|
||||
})
|
||||
}
|
||||
return
|
||||
@ -6553,7 +6570,7 @@ function tweakHomeTimelinePage() {
|
||||
updateSelectedHomeTabIndex()
|
||||
wasForYouTabSelected = selectedHomeTabIndex == 0
|
||||
},
|
||||
tabbedTimelineContainerSelector: 'div[data-testid="primaryColumn"] > div > div:last-child',
|
||||
tabbedTimelineContainerSelector: `${Selectors.PRIMARY_COLUMN} > div > div:last-child`,
|
||||
})
|
||||
|
||||
if (desktop) {
|
||||
@ -6763,12 +6780,10 @@ function tweakNotificationsPage() {
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.premiumBlueChecks != 'ignore' || settings.restoreLinkHeadlines) {
|
||||
observeTimeline(currentPage, {
|
||||
isTabbed: true,
|
||||
tabbedTimelineContainerSelector: 'div[data-testid="primaryColumn"] > div > div:last-child',
|
||||
})
|
||||
}
|
||||
observeTimeline(currentPage, {
|
||||
isTabbed: true,
|
||||
tabbedTimelineContainerSelector: `${Selectors.PRIMARY_COLUMN} > div > div:last-child`,
|
||||
})
|
||||
}
|
||||
|
||||
async function tweakOwnFocusedTweet($focusedTweet) {
|
||||
@ -6787,7 +6802,7 @@ async function tweakOwnFocusedTweet($focusedTweet) {
|
||||
})
|
||||
if (!$accountAnalyticsUpsell) return
|
||||
$accountAnalyticsUpsell.classList.add('PremiumUpsell')
|
||||
$focusedTweet.setAttribute('cpft-analytics-upsell-tagged', 'true')
|
||||
$focusedTweet.setAttribute('cpft-analytics-upsell-tagged', '')
|
||||
}
|
||||
|
||||
async function tweakProfilePage() {
|
||||
@ -6804,6 +6819,7 @@ async function tweakProfilePage() {
|
||||
let tab = currentPath.match(URL_PROFILE_RE)?.[2] || 'tweets'
|
||||
log(`on ${tab} tab`)
|
||||
observeTimeline(currentPage, {
|
||||
checkSocialContext: tab == 'tweets' || tab == 'with_replies',
|
||||
isUserTimeline: tab == 'affiliates'
|
||||
})
|
||||
|
||||
@ -6920,7 +6936,7 @@ function tweakSearchPage() {
|
||||
observeTimeline(currentPage, {
|
||||
hideHeadings: false,
|
||||
isTabbed: true,
|
||||
tabbedTimelineContainerSelector: 'div[data-testid="primaryColumn"] > div > div:last-child',
|
||||
tabbedTimelineContainerSelector: `${Selectors.PRIMARY_COLUMN} > div > div:last-child`,
|
||||
})
|
||||
|
||||
if (desktop) {
|
||||
@ -7013,7 +7029,7 @@ async function tweakTimelineTabs($timelineTabs) {
|
||||
* Restores "Tweet" button text.
|
||||
*/
|
||||
async function tweakTweetButton() {
|
||||
let $tweetButton = await getElement(`${desktop ? 'div[data-testid="primaryColumn"]': 'main'} button[data-testid^="tweetButton"]`, {
|
||||
let $tweetButton = await getElement(`${desktop ? Selectors.PRIMARY_COLUMN: 'main'} button[data-testid^="tweetButton"]`, {
|
||||
name: 'tweet button',
|
||||
stopIf: pageIsNot(currentPage),
|
||||
})
|
||||
|
2
types.d.ts
vendored
2
types.d.ts
vendored
@ -177,6 +177,7 @@ export type QuotedTweet = {
|
||||
export type SharedTweetsConfig = 'separate' | 'hide' | 'ignore'
|
||||
|
||||
export type TweetType =
|
||||
| 'COMMUNITY_TWEET'
|
||||
| 'PINNED_TWEET'
|
||||
| 'PROMOTED_TWEET'
|
||||
| 'QUOTE_TWEET'
|
||||
@ -202,6 +203,7 @@ export type TimelineItemType =
|
||||
| 'UNAVAILABLE'
|
||||
|
||||
export type TimelineOptions = {
|
||||
checkSocialContext?: boolean
|
||||
classifyTweets?: boolean
|
||||
hideHeadings?: boolean
|
||||
isTabbed?: boolean
|
||||
|
Loading…
Reference in New Issue
Block a user