Skip to content

Commit

Permalink
Revamped modal stack management to not rely on deprecated mutation ev…
Browse files Browse the repository at this point in the history
…ents (https://chromestatus.com/feature/5083947249172480)

± Expanded modal stack management to more types ↞ [auto-sync from https://github.com/adamlui/ai-web-extensions]
  • Loading branch information
kudo-sync-bot committed Dec 2, 2024
1 parent daaea3e commit db73865
Showing 1 changed file with 170 additions and 157 deletions.
327 changes: 170 additions & 157 deletions chatgpt/chatgpt-infinity/chatgpt-infinity.user.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@
// @description:zh-TW 從無所不知的 ChatGPT 生成無窮無盡的答案 (用任何語言!)
// @author Adam Lui
// @namespace https://github.com/adamlui
// @version 2024.12.2.1
// @version 2024.12.2.2
// @license MIT
// @match *://chatgpt.com/*
// @match *://chat.openai.com/*
Expand Down Expand Up @@ -384,8 +384,8 @@

// Show "Disabled (extension installed)"
if (env.extensionInstalled)
GM_registerMenuCommand(`${menu.state.symbols[0]} ${app.msgs.menuLabel_disabled}`, modals.about.show,
tooltipsSupported ? { title: ' ' } : undefined)
GM_registerMenuCommand(`${menu.state.symbols[0]} ${app.msgs.menuLabel_disabled}`,
() => modals.open('about'), tooltipsSupported ? { title: ' ' } : undefined )

// ...or add settings entries
else {
Expand Down Expand Up @@ -459,14 +459,14 @@

// Add About entry
const aboutLabel = `💡 ${app.msgs.menuLabel_about} ${app.msgs.appName}`
menu.ids.push(GM_registerMenuCommand(aboutLabel, modals.about.show,
tooltipsSupported ? { title: ' ' } : undefined))
menu.ids.push(GM_registerMenuCommand(aboutLabel, () => modals.open('about'),
tooltipsSupported ? { title: ' ' } : undefined ))

// Add Donate entry
if (!env.extensionInstalled) {
const donateLabel = `💖 ${app.msgs.menuLabel_donate}`
menu.ids.push(GM_registerMenuCommand(donateLabel, modals.donate.show,
tooltipsSupported ? { title: ' ' } : undefined))
menu.ids.push(GM_registerMenuCommand(donateLabel, () => modals.open('donate'),
tooltipsSupported ? { title: ' ' } : undefined ))
}
},

Expand Down Expand Up @@ -521,7 +521,7 @@
`${app.msgs.appName} (v${currentVer}) ${app.msgs.alert_isUpToDate}!`, // msg
'', '', updateAlertWidth
)
modals.about.show()
modals.open('about')
}})}

function toTitleCase(str) {
Expand Down Expand Up @@ -555,21 +555,39 @@
}

function siteAlert(title = '', msg = '', btns = '', checkbox = '', width = '') {
const alertID = chatgpt.alert(title, msg, btns, checkbox, width ),
alert = document.getElementById(alertID).firstChild
modals.setup(alert) // add class + starry BG + drag handlers
return alert
const alertID = chatgpt.alert(title, msg, btns, checkbox, width)
return document.getElementById(alertID).firstChild
}

// Define MODAL functions

const modals = {
stack: [],
stack: [], // of types of undismissed modals

setup(modal) {
open(modalType) {
this.stack.unshift(modalType) // add to stack
const modal = modals[modalType]() // show modal
modal.classList.add('chatgpt-infinity-modal')
modal.onmousedown = modals.dragHandlers.mousedown
dom.fillStarryBG(modal)
dom.fillStarryBG(modal) // fill BG w/ rising stars
this.observeRemoval(modal, modalType) // to maintain stack for proper nav
},

observeRemoval(modal, type) { // to maintain stack for proper nav
const modalBG = modal.parentNode
new MutationObserver(([mutation], obs) => {
mutation.removedNodes.forEach(removedNode => { if (removedNode == modalBG) {
if (modals.stack[0] == type) { // new modal not launched, implement nav back logic
modals.stack.shift() // remove this modal type from stack
const nextModalType = modals.stack[0]
if (nextModalType) { // queue exists, open next modal
modals.stack.shift() // remove next modal type from stack since re-added on next open
modals.open(nextModalType)
}
}
obs.disconnect()
}})
}).observe(modalBG.parentNode, { childList: true, subtree: true })
},

dragHandlers: {
Expand Down Expand Up @@ -601,155 +619,150 @@
}
},

about: {
show() {
modals.stack.unshift('about') ; modals.stack = [...new Set(modals.stack)] // track for nav

// Init styles
const headingStyle = 'font-size: 1.15rem',
pStyle = 'position: relative ; left: 3px',
pBrStyle = 'position: relative ; left: 4px ',
aStyle = 'color: ' + ( chatgpt.isDarkMode() ? '#c67afb' : '#8325c4' ) // purple

// Show modal
const aboutModal = siteAlert(
`${app.symbol} ${app.msgs.appName}`, // title
`<span style="${headingStyle}"><b>🏷️ <i>${app.msgs.about_version}</i></b>: </span>`
+ `<span style="${pStyle}">${app.version}</span>\n`
+ `<span style="${headingStyle}"><b>⚡ <i>${app.msgs.about_poweredBy}</i></b>: </span>`
+ `<span style="${pStyle}">`
+ `<a style="${aStyle}" href="${app.urls.chatgptJS}" target="_blank" rel="noopener">`
+ `chatgpt.js</a> v${app.chatgptJSver}</span>\n`
+ `<span style="${headingStyle}"><b>📜 <i>${app.msgs.about_sourceCode}</i></b>:</span>\n`
+ `<span style="${pBrStyle}"><a href="${app.urls.gitHub}" target="_blank" rel="nopener">`
+ app.urls.gitHub + '</a></span>',
[ // buttons
function checkForUpdates() { updateCheck() },
function getSupport(){},
function rateUs() { modals.feedback.show() },
function moreAIextensions(){}
], '', 546 // set width
)

// Format text
aboutModal.querySelector('h2').style.cssText = 'text-align: center ; font-size: 37px ; padding: 9px'
aboutModal.querySelector('p').style.cssText = 'text-align: center'

// Hack buttons
aboutModal.querySelectorAll('button').forEach(btn => {
btn.style.cssText = 'cursor: pointer !important' // since tweaks won't load on script auto-disable

// Replace link buttons w/ clones that don't dismissAlert()
if (/support|extensions/i.test(btn.textContent)) {
const btnClone = btn.cloneNode(true)
btn.parentNode.replaceChild(btnClone, btn) ; btn = btnClone
btn.onclick = () => modals.safeWinOpen(app.urls[
btn.textContent.includes(app.msgs.btnLabel_getSupport) ? 'support' : 'relatedExtensions' ])
}

// Prepend emoji + localize labels
if (/updates/i.test(btn.textContent))
btn.textContent = `🚀 ${app.msgs.btnLabel_updateCheck}`
else if (/support/i.test(btn.textContent))
btn.textContent = `🧠 ${app.msgs.btnLabel_getSupport}`
else if (/rate/i.test(btn.textContent))
btn.textContent = `⭐ ${app.msgs.btnLabel_rateUs}`
else if (/extensions/i.test(btn.textContent))
btn.textContent = `🤖 ${app.msgs.btnLabel_moreAIextensions}`

// Hide Dismiss button
else btn.style.display = 'none'
})
}
},

donate: {
longCOVIDwikiLink: 'https://en.wikipedia.org/wiki/Long_COVID',

show() {
modals.stack.unshift('donate') ; modals.stack = [...new Set(modals.stack)] // track for nav

// Show alert
const donateModal = siteAlert(
`💖 ${app.msgs.alert_showYourSupport}`, // title
`<p>${app.msgs.appName} ${app.msgs.alert_isOSS}.</p>`
+ `<p>${app.msgs.alert_despiteAffliction} `
+ `<a target="_blank" rel="noopener" href="${modals.donate.longCOVIDwikiLink}">`
+ `${app.msgs.alert_longCOVID}</a> `
+ `${app.msgs.alert_since2020}, ${app.msgs.alert_byDonatingResults}.</p>`
+ `<p>${app.msgs.alert_yourContrib}, <b>${app.msgs.alert_noMatterSize}</b>, `
+ `${app.msgs.alert_directlySupports}.</p>`
+ `<p>${app.msgs.alert_tyForSupport}!</p>`
+ '<img src="https://cdn.jsdelivr.net/gh/adamlui/adamlui/images/siggie/'
+ `${ chatgpt.isDarkMode() ? 'white' : 'black' }.png" `
+ 'style="height: 54px ; margin: 5px 0 -2px 5px"></img>'
+ `<p>—<b><a target="_blank" rel="noopener" href="${app.author.url}">`
+ `${app.msgs.appAuthor}</a></b>, ${app.msgs.alert_author}</p>`,
[ // buttons
function paypal(){},
function githubSponsors(){},
function cashApp(){},
function rateUs() { modals.feedback.show() }
], '', 478 // set width
)

// Format text
donateModal.querySelectorAll('p').forEach(p => // v-pad text, shrink line height
p.style.cssText = 'padding: 8px 0 ; line-height: 20px')

// Hack buttons
const btns = donateModal.querySelectorAll('button')
btns.forEach((btn, idx) => {

// Replace link buttons w/ clones that don't dismissAlert()
if (!/dismiss|rate/i.test(btn.textContent)) {
const btnClone = btn.cloneNode(true)
btn.parentNode.replaceChild(btnClone, btn) ; btn = btnClone
btn.onclick = () => modals.safeWinOpen(app.urls.donate[
btnClone.textContent == 'Cash App' ? 'cashApp'
: btnClone.textContent == 'GitHub' ? 'gitHub'
: 'payPal'
])
}
about() {

// Init styles
const headingStyle = 'font-size: 1.15rem',
pStyle = 'position: relative ; left: 3px',
pBrStyle = 'position: relative ; left: 4px ',
aStyle = 'color: ' + ( chatgpt.isDarkMode() ? '#c67afb' : '#8325c4' ) // purple

// Show modal
const aboutModal = siteAlert(
`${app.symbol} ${app.msgs.appName}`, // title
`<span style="${headingStyle}"><b>🏷️ <i>${app.msgs.about_version}</i></b>: </span>`
+ `<span style="${pStyle}">${app.version}</span>\n`
+ `<span style="${headingStyle}"><b>⚡ <i>${app.msgs.about_poweredBy}</i></b>: </span>`
+ `<span style="${pStyle}">`
+ `<a style="${aStyle}" href="${app.urls.chatgptJS}" target="_blank" rel="noopener">`
+ `chatgpt.js</a> v${app.chatgptJSver}</span>\n`
+ `<span style="${headingStyle}"><b>📜 <i>${app.msgs.about_sourceCode}</i></b>:</span>\n`
+ `<span style="${pBrStyle}"><a href="${app.urls.gitHub}" target="_blank" rel="nopener">`
+ app.urls.gitHub + '</a></span>',
[ // buttons
function checkForUpdates() { updateCheck() },
function getSupport(){},
function rateUs() { modals.open('feedback') },
function moreAIextensions(){}
], '', 546 // set width
)

// Format text
aboutModal.querySelector('h2').style.cssText = 'text-align: center ; font-size: 37px ; padding: 9px'
aboutModal.querySelector('p').style.cssText = 'text-align: center'

// Hack buttons
aboutModal.querySelectorAll('button').forEach(btn => {
btn.style.cssText = 'cursor: pointer !important' // since tweaks won't load on script auto-disable

// Replace link buttons w/ clones that don't dismissAlert()
if (/support|extensions/i.test(btn.textContent)) {
const btnClone = btn.cloneNode(true)
btn.parentNode.replaceChild(btnClone, btn) ; btn = btnClone
btn.onclick = () => modals.safeWinOpen(app.urls[
btn.textContent.includes(app.msgs.btnLabel_getSupport) ? 'support' : 'relatedExtensions' ])
}

// Format buttons
if (idx == 0) btn.style.display = 'none' // hide Dismiss button
else {
btn.style.cssText = 'padding: 8px 6px !important ; margin-top: -14px ;'
+ ' width: 107px ; line-height: 14px'
if (idx == btns.length -1) // de-emphasize right-most button
btn.classList.remove('primary-modal-btn')
else if (/rate/i.test(btn.textContent)) // localize 'Rate Us' label
btn.textContent = app.msgs.btnLabel_rateUs
}
})
}
// Prepend emoji + localize labels
if (/updates/i.test(btn.textContent))
btn.textContent = `🚀 ${app.msgs.btnLabel_updateCheck}`
else if (/support/i.test(btn.textContent))
btn.textContent = `🧠 ${app.msgs.btnLabel_getSupport}`
else if (/rate/i.test(btn.textContent))
btn.textContent = `⭐ ${app.msgs.btnLabel_rateUs}`
else if (/extensions/i.test(btn.textContent))
btn.textContent = `🤖 ${app.msgs.btnLabel_moreAIextensions}`

// Hide Dismiss button
else btn.style.display = 'none'
})

return aboutModal
},

feedback: {
show() {
const feedbackModal = siteAlert(
`${app.msgs.alert_choosePlatform}:`, '', // title
[ function greasyFork(){}, function productHunt(){}, function alternativeto(){} ] // buttons
)

// Hack buttons
feedbackModal.querySelectorAll('button').forEach((btn, idx) => {
if (idx == 0) btn.style.display = 'none' // hide Dismiss button

// Replace buttons w/ clones that don't dismissAlert()
donate() {

// Show modal
const donateModal = siteAlert(
`💖 ${app.msgs.alert_showYourSupport}`, // title
`<p>${app.msgs.appName} ${app.msgs.alert_isOSS}.</p>`
+ `<p>${app.msgs.alert_despiteAffliction} `
+ '<a target="_blank" rel="noopener" href="https://en.wikipedia.org/wiki/Long_COVID">'
+ `${app.msgs.alert_longCOVID}</a> `
+ `${app.msgs.alert_since2020}, ${app.msgs.alert_byDonatingResults}.</p>`
+ `<p>${app.msgs.alert_yourContrib}, <b>${app.msgs.alert_noMatterSize}</b>, `
+ `${app.msgs.alert_directlySupports}.</p>`
+ `<p>${app.msgs.alert_tyForSupport}!</p>`
+ '<img src="https://cdn.jsdelivr.net/gh/adamlui/adamlui/images/siggie/'
+ `${ chatgpt.isDarkMode() ? 'white' : 'black' }.png" `
+ 'style="height: 54px ; margin: 5px 0 -2px 5px"></img>'
+ `<p>—<b><a target="_blank" rel="noopener" href="${app.author.url}">`
+ `${app.msgs.appAuthor}</a></b>, ${app.msgs.alert_author}</p>`,
[ // buttons
function paypal(){},
function githubSponsors(){},
function cashApp(){},
function rateUs() { modals.open('feedback') }
], '', 478 // set width
)

// Format text
donateModal.querySelectorAll('p').forEach(p => // v-pad text, shrink line height
p.style.cssText = 'padding: 8px 0 ; line-height: 20px')

// Hack buttons
const btns = donateModal.querySelectorAll('button')
btns.forEach((btn, idx) => {

// Replace link buttons w/ clones that don't dismissAlert()
if (!/dismiss|rate/i.test(btn.textContent)) {
const btnClone = btn.cloneNode(true)
btn.parentNode.replaceChild(btnClone, btn) ; btn = btnClone
btn.onclick = () => modals.safeWinOpen(app.urls.review[
btn.textContent == 'Greasy Fork' ? 'greasyFork'
: btn.textContent == 'Product Hunt' ? 'productHunt'
: 'alternativeTo'
btn.onclick = () => modals.safeWinOpen(app.urls.donate[
btnClone.textContent == 'Cash App' ? 'cashApp'
: btnClone.textContent == 'GitHub' ? 'gitHub'
: 'payPal'
])
})
}

// Nav back
feedbackModal.addEventListener('DOMNodeRemoved', () => modals[modals.stack[0]]?.show() )
}
// Format buttons
if (idx == 0) btn.style.display = 'none' // hide Dismiss button
else {
btn.style.cssText = 'padding: 8px 6px !important ; margin-top: -14px ;'
+ ' width: 107px ; line-height: 14px'
if (idx == btns.length -1) // de-emphasize right-most button
btn.classList.remove('primary-modal-btn')
else if (/rate/i.test(btn.textContent)) // localize 'Rate Us' label
btn.textContent = app.msgs.btnLabel_rateUs
}
})

return donateModal
},

feedback() {

// Show modal
const feedbackModal = siteAlert(
`${app.msgs.alert_choosePlatform}:`, '', // title
[ function greasyFork(){}, function productHunt(){}, function alternativeto(){} ] // buttons
)

// Hack buttons
feedbackModal.querySelectorAll('button').forEach((btn, idx) => {
if (idx == 0) btn.style.display = 'none' // hide Dismiss button

// Replace buttons w/ clones that don't dismissAlert()
const btnClone = btn.cloneNode(true)
btn.parentNode.replaceChild(btnClone, btn) ; btn = btnClone
btn.onclick = () => modals.safeWinOpen(app.urls.review[
btn.textContent == 'Greasy Fork' ? 'greasyFork'
: btn.textContent == 'Product Hunt' ? 'productHunt'
: 'alternativeTo'
])
})

return feedbackModal
},

safeWinOpen(url) { open(url, '_blank', 'noopener') } // to prevent backdoor vulnerabilities
Expand Down

0 comments on commit db73865

Please sign in to comment.