Skip to content

Commit 588e574

Browse files
committed
Improved menus.pin
± Added `status` + store elems to avoid re-creation ± Condensed `pinMenuIcons` init ± Centralized listeners + UL init to `.createAppend()`
1 parent 6d523db commit 588e574

File tree

3 files changed

+108
-114
lines changed

3 files changed

+108
-114
lines changed

bravegpt/greasemonkey/bravegpt.user.js

Lines changed: 36 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@
148148
// @description:zu Yengeza izimpendulo ze-AI ku-Brave Search (inikwa amandla yi-GPT-4o!)
149149
// @author KudoAI
150150
// @namespace https://kudoai.com
151-
// @version 2025.3.31.2
151+
// @version 2025.3.31.3
152152
// @license MIT
153153
// @icon https://cdn.jsdelivr.net/gh/KudoAI/bravegpt@df624b0/assets/images/icons/bravegpt/icon48.png
154154
// @icon64 https://cdn.jsdelivr.net/gh/KudoAI/bravegpt@df624b0/assets/images/icons/bravegpt/icon64.png
@@ -1610,9 +1610,7 @@
16101610
const menus = {
16111611
pin: {
16121612
clickHandler(event) {
1613-
const pinMenu = event.target.closest(`#${app.slug}-pin-menu`),
1614-
itemLabel = event.target.textContent,
1615-
prevOffsetTop = appDiv.offsetTop
1613+
const itemLabel = event.target.textContent, prevOffsetTop = appDiv.offsetTop
16161614

16171615
// Switch mode
16181616
if (itemLabel == app.msgs.menuLabel_top) toggle.sidebar('sticky')
@@ -1621,29 +1619,29 @@
16211619
else if (itemLabel == app.msgs.menuLabel_bottom) toggle.anchorMode()
16221620

16231621
// Close/update menu
1624-
if (appDiv.offsetTop != prevOffsetTop) pinMenu.remove() // since app moved
1625-
else menus.pin.update(pinMenu) // since menu stayed in place
1622+
if (appDiv.offsetTop != prevOffsetTop) menus.pin.hide() // since app moved
1623+
menus.pin.update()
16261624
},
16271625

16281626
createAppend() {
1629-
const pinMenu = dom.create.elem('div', { id: `${app.slug}-pin-menu`,
1627+
this.div = dom.create.elem('div', { id: `${app.slug}-pin-menu`,
16301628
class: `${app.slug}-menu ${app.slug}-btn-tooltip fade-in-less no-user-select` })
1631-
menus.pin.update(pinMenu) ; appDiv.append(pinMenu)
1632-
return pinMenu
1629+
this.ul = dom.create.elem('ul')
1630+
this.div.append(this.ul) ; appDiv.append(this.div)
1631+
this.div.onmouseenter = this.div.onmouseleave = this.toggle
1632+
this.update() ; this.status = 'hidden'
16331633
},
16341634

1635-
update(pinMenu) {
1636-
pinMenu.textContent = ''
1635+
hide() { Object.assign(this.div.style, { display: 'none', opacity: 0 }) ; this.status = 'hidden' },
16371636

1638-
// Init core elems
1639-
const pinMenuUL = document.querySelector(`#${app.slug}-pin-menu ul`)
1640-
|| dom.create.elem('ul')
1637+
update() {
1638+
1639+
// Init elems
1640+
this.ul.textContent = ''
16411641
const pinMenuItems = []
1642-
const pinMenulabels = [
1643-
`${app.msgs.menuLabel_pinTo}...`, app.msgs.menuLabel_top,
1644-
app.msgs.menuLabel_sidebar, app.msgs.menuLabel_bottom ]
1645-
const pinMenuIcons = [
1646-
icons.webCorner.create(), icons.sidebar.create(), icons.anchor.create(), icons.checkmark.create()]
1642+
const pinMenuIcons = ['webCorner', 'sidebar', 'anchor', 'checkmark'].map(key => icons[key].create())
1643+
const pinMenulabels = [ `${app.msgs.menuLabel_pinTo}...`,
1644+
app.msgs.menuLabel_top, app.msgs.menuLabel_sidebar, app.msgs.menuLabel_bottom ]
16471645

16481646
// Style icons
16491647
pinMenuIcons.forEach(icon => icon.style.cssText = (
@@ -1668,29 +1666,29 @@
16681666
|| i == 3 && config.anchored) // 'Bottom' item + Anchor mode on
16691667
pinMenuItems[i].append(pinMenuIcons[pinMenuIcons.length -1]) // append right checkmark
16701668
pinMenuItems[i].onclick = menus.pin.clickHandler
1671-
pinMenuUL.append(pinMenuItems[i])
1669+
this.ul.append(pinMenuItems[i])
16721670
}
1673-
pinMenu.append(pinMenuUL)
1674-
1675-
// Add listeners
1676-
pinMenu.onmouseenter = pinMenu.onmouseleave = menus.pin.toggle
16771671
},
16781672

16791673
toggle(event) { // visibility
1680-
clearTimeout(menus.pin.hideTimeout) // in case rapid re-enter before ran
1681-
const pinMenu = appDiv.querySelector(`#${app.slug}-pin-menu`) || menus.pin.createAppend()
1682-
if (event.type == 'mouseleave') // schedule delayed removal to cover gap
1683-
return menus.pin.hideTimeout = setTimeout(() => pinMenu.remove(), 55)
1684-
const pinBtn = appDiv.querySelector(`#${app.slug}-pin-btn`)
1685-
const rects = {
1686-
appDiv: appDiv.getBoundingClientRect(), pinBtn: pinBtn.getBoundingClientRect(),
1687-
pinMenu: pinMenu.getBoundingClientRect()
1688-
}
1689-
const appIsHigh = rects.pinBtn.top < ( rects.pinMenu.height +15 )
1690-
pinMenu.style.top = `${ rects.pinBtn.top - rects.appDiv.top +(
1691-
appIsHigh ? /* point down */ 29 : /* point up */ - rects.pinMenu.height -13 )}px`
1692-
if (!menus.pin.rightPos) menus.pin.rightPos = rects.appDiv.right - event.clientX - pinMenu.offsetWidth/2
1693-
Object.assign(pinMenu.style, { right: `${menus.pin.rightPos}px`, opacity: 1 })
1674+
clearTimeout(menus.pin.hide.timeout) // in case rapid re-enter before ran
1675+
if (!menus.pin.div) menus.pin.createAppend()
1676+
if (event.type == 'mouseenter' && menus.pin.status == 'hidden' && event.target != menus.pin.div) {
1677+
menus.pin.div.style.display = '' // for rects calc
1678+
const pinBtn = appDiv.querySelector(`#${app.slug}-pin-btn`)
1679+
const rects = {
1680+
appDiv: appDiv.getBoundingClientRect(), pinBtn: pinBtn.getBoundingClientRect(),
1681+
pinMenu: menus.pin.div.getBoundingClientRect()
1682+
}
1683+
const appIsHigh = rects.pinBtn.top < ( rects.pinMenu.height +15 )
1684+
menus.pin.div.style.top = `${ rects.pinBtn.top - rects.appDiv.top +(
1685+
appIsHigh ? /* point down */ 29 : /* point up */ - rects.pinMenu.height -13 )}px`
1686+
if (!menus.pin.rightPos)
1687+
menus.pin.rightPos = rects.appDiv.right - event.clientX - menus.pin.div.offsetWidth/2
1688+
Object.assign(menus.pin.div.style, { right: `${menus.pin.rightPos}px`, opacity: 1 })
1689+
menus.pin.status = 'visible'
1690+
} else if (event.type == 'mouseleave')
1691+
return menus.pin.hide.timeout = setTimeout(() => menus.pin.hide(), 55)
16941692
}
16951693
}
16961694
}

duckduckgpt/greasemonkey/duckduckgpt.user.js

Lines changed: 36 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@
148148
// @description:zu Yengeza izimpendulo ze-AI ku-DuckDuckGo (inikwa amandla yi-GPT-4o!)
149149
// @author KudoAI
150150
// @namespace https://kudoai.com
151-
// @version 2025.3.31.1
151+
// @version 2025.3.31.2
152152
// @license MIT
153153
// @icon https://cdn.jsdelivr.net/gh/KudoAI/duckduckgpt@06af076/assets/images/icons/duckduckgpt/icon48.png
154154
// @icon64 https://cdn.jsdelivr.net/gh/KudoAI/duckduckgpt@06af076/assets/images/icons/duckduckgpt/icon64.png
@@ -1613,9 +1613,7 @@
16131613
const menus = {
16141614
pin: {
16151615
clickHandler(event) {
1616-
const pinMenu = event.target.closest(`#${app.slug}-pin-menu`),
1617-
itemLabel = event.target.textContent,
1618-
prevOffsetTop = appDiv.offsetTop
1616+
const itemLabel = event.target.textContent, prevOffsetTop = appDiv.offsetTop
16191617

16201618
// Switch mode
16211619
if (itemLabel == app.msgs.menuLabel_top) toggle.sidebar('sticky')
@@ -1624,29 +1622,29 @@
16241622
else if (itemLabel == app.msgs.menuLabel_bottom) toggle.anchorMode()
16251623

16261624
// Close/update menu
1627-
if (appDiv.offsetTop != prevOffsetTop) pinMenu.remove() // since app moved
1628-
else menus.pin.update(pinMenu) // since menu stayed in place
1625+
if (appDiv.offsetTop != prevOffsetTop) menus.pin.hide() // since app moved
1626+
menus.pin.update()
16291627
},
16301628

16311629
createAppend() {
1632-
const pinMenu = dom.create.elem('div', { id: `${app.slug}-pin-menu`,
1630+
this.div = dom.create.elem('div', { id: `${app.slug}-pin-menu`,
16331631
class: `${app.slug}-menu ${app.slug}-btn-tooltip fade-in-less no-user-select` })
1634-
menus.pin.update(pinMenu) ; appDiv.append(pinMenu)
1635-
return pinMenu
1632+
this.ul = dom.create.elem('ul')
1633+
this.div.append(this.ul) ; appDiv.append(this.div)
1634+
this.div.onmouseenter = this.div.onmouseleave = this.toggle
1635+
this.update() ; this.status = 'hidden'
16361636
},
16371637

1638-
update(pinMenu) {
1639-
pinMenu.textContent = ''
1638+
hide() { Object.assign(this.div.style, { display: 'none', opacity: 0 }) ; this.status = 'hidden' },
16401639

1641-
// Init core elems
1642-
const pinMenuUL = document.querySelector(`#${app.slug}-pin-menu ul`)
1643-
|| dom.create.elem('ul')
1640+
update() {
1641+
1642+
// Init elems
1643+
this.ul.textContent = ''
16441644
const pinMenuItems = []
1645-
const pinMenulabels = [
1646-
`${app.msgs.menuLabel_pinTo}...`, app.msgs.menuLabel_top,
1647-
app.msgs.menuLabel_sidebar, app.msgs.menuLabel_bottom ]
1648-
const pinMenuIcons = [
1649-
icons.webCorner.create(), icons.sidebar.create(), icons.anchor.create(), icons.checkmark.create()]
1645+
const pinMenuIcons = ['webCorner', 'sidebar', 'anchor', 'checkmark'].map(key => icons[key].create())
1646+
const pinMenulabels = [ `${app.msgs.menuLabel_pinTo}...`,
1647+
app.msgs.menuLabel_top, app.msgs.menuLabel_sidebar, app.msgs.menuLabel_bottom ]
16501648

16511649
// Style icons
16521650
pinMenuIcons.forEach(icon => icon.style.cssText = (
@@ -1671,29 +1669,29 @@
16711669
|| i == 3 && config.anchored) // 'Bottom' item + Anchor mode on
16721670
pinMenuItems[i].append(pinMenuIcons[pinMenuIcons.length -1]) // append right checkmark
16731671
pinMenuItems[i].onclick = menus.pin.clickHandler
1674-
pinMenuUL.append(pinMenuItems[i])
1672+
this.ul.append(pinMenuItems[i])
16751673
}
1676-
pinMenu.append(pinMenuUL)
1677-
1678-
// Add listeners
1679-
pinMenu.onmouseenter = pinMenu.onmouseleave = menus.pin.toggle
16801674
},
16811675

16821676
toggle(event) { // visibility
1683-
clearTimeout(menus.pin.hideTimeout) // in case rapid re-enter before ran
1684-
const pinMenu = appDiv.querySelector(`#${app.slug}-pin-menu`) || menus.pin.createAppend()
1685-
if (event.type == 'mouseleave') // schedule delayed removal to cover gap
1686-
return menus.pin.hideTimeout = setTimeout(() => pinMenu.remove(), 55)
1687-
const pinBtn = appDiv.querySelector(`#${app.slug}-pin-btn`)
1688-
const rects = {
1689-
appDiv: appDiv.getBoundingClientRect(), pinBtn: pinBtn.getBoundingClientRect(),
1690-
pinMenu: pinMenu.getBoundingClientRect()
1691-
}
1692-
const appIsHigh = rects.pinBtn.top < ( rects.pinMenu.height +15 )
1693-
pinMenu.style.top = `${ rects.pinBtn.top - rects.appDiv.top +(
1694-
appIsHigh ? /* point down */ 29 : /* point up */ - rects.pinMenu.height -13 )}px`
1695-
if (!menus.pin.rightPos) menus.pin.rightPos = rects.appDiv.right - event.clientX - pinMenu.offsetWidth/2
1696-
Object.assign(pinMenu.style, { right: `${menus.pin.rightPos}px`, opacity: 1 })
1677+
clearTimeout(menus.pin.hide.timeout) // in case rapid re-enter before ran
1678+
if (!menus.pin.div) menus.pin.createAppend()
1679+
if (event.type == 'mouseenter' && menus.pin.status == 'hidden' && event.target != menus.pin.div) {
1680+
menus.pin.div.style.display = '' // for rects calc
1681+
const pinBtn = appDiv.querySelector(`#${app.slug}-pin-btn`)
1682+
const rects = {
1683+
appDiv: appDiv.getBoundingClientRect(), pinBtn: pinBtn.getBoundingClientRect(),
1684+
pinMenu: menus.pin.div.getBoundingClientRect()
1685+
}
1686+
const appIsHigh = rects.pinBtn.top < ( rects.pinMenu.height +15 )
1687+
menus.pin.div.style.top = `${ rects.pinBtn.top - rects.appDiv.top +(
1688+
appIsHigh ? /* point down */ 29 : /* point up */ - rects.pinMenu.height -13 )}px`
1689+
if (!menus.pin.rightPos)
1690+
menus.pin.rightPos = rects.appDiv.right - event.clientX - menus.pin.div.offsetWidth/2
1691+
Object.assign(menus.pin.div.style, { right: `${menus.pin.rightPos}px`, opacity: 1 })
1692+
menus.pin.status = 'visible'
1693+
} else if (event.type == 'mouseleave')
1694+
return menus.pin.hide.timeout = setTimeout(() => menus.pin.hide(), 55)
16971695
}
16981696
}
16991697
}

googlegpt/greasemonkey/googlegpt.user.js

Lines changed: 36 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@
149149
// @description:zu Yengeza izimpendulo ze-AI ku-Google Search (inikwa amandla yi-Google Gemma + GPT-4o!)
150150
// @author KudoAI
151151
// @namespace https://kudoai.com
152-
// @version 2025.3.31.1
152+
// @version 2025.3.31.2
153153
// @license MIT
154154
// @icon https://cdn.jsdelivr.net/gh/KudoAI/googlegpt@59409b2/assets/images/icons/googlegpt/black/icon48.png
155155
// @icon64 https://cdn.jsdelivr.net/gh/KudoAI/googlegpt@59409b2/assets/images/icons/googlegpt/black/icon64.png
@@ -1757,9 +1757,7 @@
17571757
const menus = {
17581758
pin: {
17591759
clickHandler(event) {
1760-
const pinMenu = event.target.closest(`#${app.slug}-pin-menu`),
1761-
itemLabel = event.target.textContent,
1762-
prevOffsetTop = appDiv.offsetTop
1760+
const itemLabel = event.target.textContent, prevOffsetTop = appDiv.offsetTop
17631761

17641762
// Switch mode
17651763
if (itemLabel == app.msgs.menuLabel_top) toggle.sidebar('sticky')
@@ -1768,29 +1766,29 @@
17681766
else if (itemLabel == app.msgs.menuLabel_bottom) toggle.anchorMode()
17691767

17701768
// Close/update menu
1771-
if (appDiv.offsetTop != prevOffsetTop) pinMenu.remove() // since app moved
1772-
else menus.pin.update(pinMenu) // since menu stayed in place
1769+
if (appDiv.offsetTop != prevOffsetTop) menus.pin.hide() // since app moved
1770+
menus.pin.update()
17731771
},
17741772

17751773
createAppend() {
1776-
const pinMenu = dom.create.elem('div', { id: `${app.slug}-pin-menu`,
1774+
this.div = dom.create.elem('div', { id: `${app.slug}-pin-menu`,
17771775
class: `${app.slug}-menu ${app.slug}-btn-tooltip fade-in-less no-user-select` })
1778-
menus.pin.update(pinMenu) ; appDiv.append(pinMenu)
1779-
return pinMenu
1776+
this.ul = dom.create.elem('ul')
1777+
this.div.append(this.ul) ; appDiv.append(this.div)
1778+
this.div.onmouseenter = this.div.onmouseleave = this.toggle
1779+
this.update() ; this.status = 'hidden'
17801780
},
17811781

1782-
update(pinMenu) {
1783-
pinMenu.textContent = ''
1782+
hide() { Object.assign(this.div.style, { display: 'none', opacity: 0 }) ; this.status = 'hidden' },
17841783

1785-
// Init core elems
1786-
const pinMenuUL = document.querySelector(`#${app.slug}-pin-menu ul`)
1787-
|| dom.create.elem('ul')
1784+
update() {
1785+
1786+
// Init elems
1787+
this.ul.textContent = ''
17881788
const pinMenuItems = []
1789-
const pinMenulabels = [
1790-
`${app.msgs.menuLabel_pinTo}...`, app.msgs.menuLabel_top,
1791-
app.msgs.menuLabel_sidebar, app.msgs.menuLabel_bottom ]
1792-
const pinMenuIcons = [
1793-
icons.webCorner.create(), icons.sidebar.create(), icons.anchor.create(), icons.checkmark.create()]
1789+
const pinMenuIcons = ['webCorner', 'sidebar', 'anchor', 'checkmark'].map(key => icons[key].create())
1790+
const pinMenulabels = [ `${app.msgs.menuLabel_pinTo}...`,
1791+
app.msgs.menuLabel_top, app.msgs.menuLabel_sidebar, app.msgs.menuLabel_bottom ]
17941792

17951793
// Style icons
17961794
pinMenuIcons.forEach(icon => icon.style.cssText = (
@@ -1815,29 +1813,29 @@
18151813
|| i == 3 && config.anchored) // 'Bottom' item + Anchor mode on
18161814
pinMenuItems[i].append(pinMenuIcons[pinMenuIcons.length -1]) // append right checkmark
18171815
pinMenuItems[i].onclick = menus.pin.clickHandler
1818-
pinMenuUL.append(pinMenuItems[i])
1816+
this.ul.append(pinMenuItems[i])
18191817
}
1820-
pinMenu.append(pinMenuUL)
1821-
1822-
// Add listeners
1823-
pinMenu.onmouseenter = pinMenu.onmouseleave = menus.pin.toggle
18241818
},
18251819

18261820
toggle(event) { // visibility
1827-
clearTimeout(menus.pin.hideTimeout) // in case rapid re-enter before ran
1828-
const pinMenu = appDiv.querySelector(`#${app.slug}-pin-menu`) || menus.pin.createAppend()
1829-
if (event.type == 'mouseleave') // schedule delayed removal to cover gap
1830-
return menus.pin.hideTimeout = setTimeout(() => pinMenu.remove(), 55)
1831-
const pinBtn = appDiv.querySelector(`#${app.slug}-pin-btn`)
1832-
const rects = {
1833-
appDiv: appDiv.getBoundingClientRect(), pinBtn: pinBtn.getBoundingClientRect(),
1834-
pinMenu: pinMenu.getBoundingClientRect()
1835-
}
1836-
const appIsHigh = rects.pinBtn.top < ( rects.pinMenu.height +15 )
1837-
pinMenu.style.top = `${ rects.pinBtn.top - rects.appDiv.top +(
1838-
appIsHigh ? /* point down */ 29 : /* point up */ - rects.pinMenu.height -13 )}px`
1839-
if (!menus.pin.rightPos) menus.pin.rightPos = rects.appDiv.right - event.clientX - pinMenu.offsetWidth/2
1840-
Object.assign(pinMenu.style, { right: `${menus.pin.rightPos}px`, opacity: 1 })
1821+
clearTimeout(menus.pin.hide.timeout) // in case rapid re-enter before ran
1822+
if (!menus.pin.div) menus.pin.createAppend()
1823+
if (event.type == 'mouseenter' && menus.pin.status == 'hidden' && event.target != menus.pin.div) {
1824+
menus.pin.div.style.display = '' // for rects calc
1825+
const pinBtn = appDiv.querySelector(`#${app.slug}-pin-btn`)
1826+
const rects = {
1827+
appDiv: appDiv.getBoundingClientRect(), pinBtn: pinBtn.getBoundingClientRect(),
1828+
pinMenu: menus.pin.div.getBoundingClientRect()
1829+
}
1830+
const appIsHigh = rects.pinBtn.top < ( rects.pinMenu.height +15 )
1831+
menus.pin.div.style.top = `${ rects.pinBtn.top - rects.appDiv.top +(
1832+
appIsHigh ? /* point down */ 29 : /* point up */ - rects.pinMenu.height -13 )}px`
1833+
if (!menus.pin.rightPos)
1834+
menus.pin.rightPos = rects.appDiv.right - event.clientX - menus.pin.div.offsetWidth/2
1835+
Object.assign(menus.pin.div.style, { right: `${menus.pin.rightPos}px`, opacity: 1 })
1836+
menus.pin.status = 'visible'
1837+
} else if (event.type == 'mouseleave')
1838+
return menus.pin.hide.timeout = setTimeout(() => menus.pin.hide(), 55)
18411839
}
18421840
}
18431841
}

0 commit comments

Comments
 (0)