|
// ==UserScript== |
|
// @name Bard copy button |
|
// @namespace mailto:[email protected] |
|
// @version 0.1 |
|
// @description Add a copy button to Google Bard's response without clicking more |
|
// @author Explosion-Scratch |
|
// @match https://bard.google.com/* |
|
// @icon https://www.google.com/s2/favicons?sz=64&domain=bard.google.com |
|
// @grant none |
|
// ==/UserScript== |
|
|
|
(function () { |
|
"use strict"; |
|
const style = `.gmat-mdc-tooltip,[mattooltip=More] {opacity: 0}`; |
|
const s = document.createElement("style"); |
|
s.innerHTML = style; |
|
document.head.appendChild(s); |
|
|
|
observeMutations("body", () => { |
|
[...document.querySelectorAll(".response-container")].forEach( |
|
initContainer, |
|
); |
|
}); |
|
|
|
function initContainer(container) { |
|
if (container.getAttribute("data-added-listeners")) { |
|
return; |
|
} |
|
let button = document.createElement("button"); |
|
|
|
Object.entries({ |
|
class: |
|
"mat-mdc-tooltip-trigger icon-button mdc-button mat-mdc-button gmat-mdc-button-with-prefix mat-unthemed mat-mdc-button-base gmat-mdc-button ng-star-inserted", |
|
mattooltip: "Copy response", |
|
"aria-label": "Copy response", |
|
"mat-button": "", |
|
style: 'border-radius: 1000px !important; color: var(--bard-color-on-surface-variant); min-height: 40px; min-width: 40px; border-radius: 50%; -webkit-flex-shrink: 0; -ms-flex-negative: 0;', |
|
"mat-ripple-loader-class-name": "mat-mdc-button-ripple", |
|
}).forEach(([k, v]) => button.setAttribute(k, v)); |
|
button.innerHTML = `<span class="mat-mdc-button-persistent-ripple mdc-button__ripple"></span |
|
> |
|
<span class="mat-mdc-button-persistent-ripple mdc-button__ripple"></span> |
|
<mat-icon |
|
role="img" |
|
class="mat-icon notranslate icon-only-button-icon google-symbols mat-icon-no-color" |
|
style="height: 20px; width: 20px; font-size: 20px;" |
|
aria-hidden="true" |
|
data-mat-icon-type="font" |
|
data-mat-icon-name="content_copy" |
|
>content_copy</mat-icon |
|
><span class="mdc-button__label"></span |
|
><span class="mat-mdc-focus-indicator"></span |
|
><span class="mat-mdc-button-touch-target"></span |
|
><span class="mat-ripple mat-mdc-button-ripple"></span> |
|
`; |
|
button.id = "copy_button"; |
|
button.onclick = async () => { |
|
console.log('Clicked'); |
|
container.querySelector("[mattooltip=More]").click(); |
|
console.log('Clicked more'); |
|
await new Promise((r) => setTimeout(r, 10)); |
|
console.log('Clicked copy'); |
|
document.querySelector(".mat-mdc-menu-item[aria-label=Copy]").click(); |
|
console.log('Done'); |
|
await new Promise((r) => setTimeout(r, 10)); |
|
}; |
|
container.querySelector("[class*=buttons-container]").prepend(button); |
|
container.setAttribute("data-added-listeners", "true"); |
|
} |
|
|
|
function observeMutations(selector, callback = () => {}) { |
|
const targetNode = document.querySelector(selector); |
|
|
|
if (!targetNode) { |
|
console.error("Invalid selector. Element not found."); |
|
return; |
|
} |
|
|
|
const observerConfig = { attributes: true, childList: true, subtree: true }; |
|
|
|
const mutationCallback = (mutationsList, observer) => { |
|
callback(mutationsList, observer); |
|
}; |
|
|
|
const observer = new MutationObserver(mutationCallback); |
|
|
|
observer.observe(targetNode, observerConfig); |
|
|
|
const cancelFunction = () => { |
|
observer.disconnect(); |
|
console.log("Mutation observation cancelled."); |
|
}; |
|
|
|
return cancelFunction; |
|
} |
|
})(); |
Awesome,thanks for the help. After finding one for openai, chatgpt to put copy button on their UI, this means no more bad UX decisions for now in the two of them. Though I had to get chatgpt or bard can't remember to restyle it, as it was butt ugly. :)