Paste text into Grok textarea from main page
// ==UserScript==
// @name grok Paste
// @description Paste text into Grok textarea from main page
// @match *://grok.com/*
// @version 0.0.1.20251015075309
// @namespace https://greasyfork.org/users/1435046
// ==/UserScript==
(function () {
'use strict';
let queueArray = [];
let cycleInProgress = false;
window.addEventListener("message", event => {
const data = event.data;
if (event.data && event.data.type === 'reasonButtonClicked') {
document.querySelector('button[aria-label="Think"]').click();
return;
}
if (event.data && event.data.type === 'newChatButtonClicked') {
const customNewChatButton = document.querySelector('a[href="/"]');
if (customNewChatButton) customNewChatButton.click();
queueArray = [];
cycleInProgress = false;
}
//grab style element
let grokCssStyleId = document.getElementById('grokCssStyleId');
let chatMessageInput = document.querySelector('div:has(> div > div > form > div > div > div > div > textarea[aria-label="Ask Grok anything"])');
let chatMessageInputRule = 'div:has(> div > div > form > div > div > div > div > textarea[aria-label="Ask Grok anything"]) {display: none !important;}';
let chatMessageInputBackdrop = document.querySelector('.chat-input-backdrop');
let chatMessageInputBackdropRule = '.chat-input-backdrop {display: none !important;}';
let header = document.querySelector('div:has(> div > div > button[aria-label="Toggle sidebar"] > svg > path[d="M3 12h18"])');
//if event data type is defaultChatMessageInputDisplay
if (event.data?.type === 'defaultChatMessageInputDisplay') {
console.log('default');
if (chatMessageInput) {
//delete the rule here
grokCssStyleId.innerHTML = grokCssStyleId.innerHTML.replace(`${chatMessageInputRule}`, '')
grokCssStyleId.innerHTML = grokCssStyleId.innerHTML.replace(`${chatMessageInputBackdropRule}`, '')
header.style.removeProperty('display');
//return
return;
}
}
if (event.data?.type === 'customizeChatMessageInputDisplay') {
console.log('customize');
if (chatMessageInput) {
console.log('chatMessageInput found')
grokCssStyleId.innerHTML += `${chatMessageInputRule}`
grokCssStyleId.innerHTML += `${chatMessageInputBackdropRule}`
header.style.display = 'none';
//return
return;
}
}
if (event.data.type === "prompt" && event.data.content.trim()) {
queueArray.push(event.data.content);
console.log(cycleInProgress)
function queue() {
if (cycleInProgress || queueArray.length === 0) { return };
cycleInProgress = true;
const textarea = document.querySelector('textarea[aria-label="Ask Grok anything"]');
if (!textarea) return;
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLTextAreaElement.prototype, "value").set;
nativeInputValueSetter.call(textarea, queueArray[0]); // Set like the browser would
// Now trigger a React-compatible InputEvent
const inputEvent = new InputEvent('input', {
bubbles: true,
cancelable: true,
inputType: 'insertText',
data: queueArray[0],
});
textarea.dispatchEvent(inputEvent);
document.querySelector('button[aria-label="Submit"]').click();
const stopButtonSelector = 'button[aria-label="Stop model response"]';
let observer = new MutationObserver(function (mutationRecordArray) {
//for each mutation
mutationRecordArray.forEach(function (mutationRecord) {
mutationRecord.removedNodes.forEach((node) => {
console.log('removed node: ', node);
if (node.matches && node.matches(stopButtonSelector)) {
console.log('button with aria label stop model response has been removed');
//disconect the observer since the cycle has finished and a response has been generated
observer.disconnect();
//as the response has completed lets remove the first value in the queue which we presumably just got a
//response for
console.log(queueArray.shift())
//lets indicate theat the cycle has ended
cycleInProgress = false;
//lets call the queue function again to see if there are more items in the queue array
queue();
};
});
})
})
observer.observe(document.body, { childList: true, subtree: true })
}
queue();
}
});
})();