Skip to content

Instantly share code, notes, and snippets.

@ajorpheus
Last active June 17, 2025 13:01
Show Gist options
  • Select an option

  • Save ajorpheus/047bef282505e35e5881acec9fafca09 to your computer and use it in GitHub Desktop.

Select an option

Save ajorpheus/047bef282505e35e5881acec9fafca09 to your computer and use it in GitHub Desktop.
// Following grants are needed for some of the functions below to function
// @grant GM_openInTab
// @grant GM_xmlhttpRequest
// @grant GM_notification
// Default configuration object that can be overridden
window.TM_CONFIG = window.TM_CONFIG || {
debug: true,
notificationTimeout: 3000,
clickMethods: {
standardClick: true, // Method 1: element.click()
jQueryClick: true, // Method 2: $(element).click()
mouseEvents: false, // Method 3: Simulate mousedown/mouseup/click events
directNavigation: false // Method 4: Navigate directly to href
}
};
function log_noti_simple(text, timeout = 2000) {
console.log(`Running "${GM_info.script.name}"`)
// Timeout should be at least 1 second (1000ms) for it to be useful
timeout = timeout < 1000 ? 1000 : timeout;
GM_notification({
title: `${GM_info.script.name}`,
text: text,
timeout: timeout,
onclick: () => {
console.log("My notice was clicked.");
window.focus();
}
})
}
// Enhanced logging function with notification support
function log(message, showNotification = false) {
const timestamp = new Date().toLocaleTimeString();
const formattedMessage = `[${GM_info.script.name} ${timestamp}] ${message}`;
// Always log to console
console.log(formattedMessage);
// Show notification if enabled and requested
if (window.TM_CONFIG.debug && showNotification) {
GM_notification({
title: GM_info.script.name,
text: message,
timeout: window.TM_CONFIG.notificationTimeout
});
}
}
// Safely get element text content
function safeGetText(element) {
if (!element) return '';
return element.textContent || element.innerText || '';
}
// Safely get element attribute
function safeGetAttribute(element, attr) {
if (!element || typeof element.getAttribute !== 'function') return '';
return element.getAttribute(attr) || '';
}
// Advanced click function with multiple methods
function advancedClick(element) {
if (!element) {
log('Cannot click: Element is null or undefined', true);
return;
}
log('Attempting configured click methods on the element...', false);
// Method 1: Standard click()
if (window.TM_CONFIG.clickMethods.standardClick) {
try {
element.click();
log('Method 1: Standard click() called', true);
} catch (e) {
log(`Method 1 failed: ${e.message}`, false);
}
} else {
log('Method 1: Standard click() SKIPPED (disabled in config)', false);
}
// Method 2: jQuery click (if jQuery exists)
if (window.TM_CONFIG.clickMethods.jQueryClick) {
try {
if (typeof $ !== 'undefined') {
$(element).click();
log('Method 2: jQuery click() called', true);
} else {
log('Method 2: jQuery not available', false);
}
} catch (e) {
log(`Method 2 failed: ${e.message}`, false);
}
} else {
log('Method 2: jQuery click() SKIPPED (disabled in config)', false);
}
// Method 3: Trigger mousedown + mouseup + click events
if (window.TM_CONFIG.clickMethods.mouseEvents) {
try {
['mousedown', 'mouseup', 'click'].forEach(eventType => {
const event = new MouseEvent(eventType, {
view: window,
bubbles: true,
cancelable: true,
buttons: 1
});
element.dispatchEvent(event);
});
log('Method 3: MouseEvents dispatched', true);
} catch (e) {
log(`Method 3 failed: ${e.message}`, false);
}
} else {
log('Method 3: MouseEvents SKIPPED (disabled in config)', false);
}
// Method 4: Navigate directly to the href
if (window.TM_CONFIG.clickMethods.directNavigation) {
try {
const href = safeGetAttribute(element, 'href');
if (href) {
log(`Method 4: Navigating directly to ${href}`, true);
window.location.href = href;
} else {
log('Method 4: No href attribute found', false);
}
} catch (e) {
log(`Method 4 failed: ${e.message}`, false);
}
} else {
log('Method 4: Direct navigation SKIPPED (disabled in config)', false);
}
log('All configured click methods attempted', true);
}
function processJSON_Response(response) {
console.log('Received response');
console.log([
response.status,
response.statusText,
response.readyState,
response.responseHeaders,
response.responseText,
response.finalUrl
].join("\n"));
}
function reportAJAX_Error(rspObj) {
console.error(`TM scrpt => Error ${rspObj.status}! ${rspObj.statusText}`);
}
function callMacro(jNode, macroLocation, callback = null) {
console.log("Calling macro for " + window.location + " for jNode " + jNode)
curl(macroLocation, callback);
}
function curl(apiURL, callback = null) {
GM_xmlhttpRequest({
method: "GET",
url: apiURL,
responseType: "text",
onload: (response) => {
processJSON_Response(response);
if (callback) {
console.log('Inside callback');
callback();
}
},
onabort: reportAJAX_Error,
onerror: reportAJAX_Error,
ontimeout: reportAJAX_Error
});
}
function closeTab() {
log("Closing tab now...");
window.close();
}
function clickIt(jNode) {
//alert("I am going to click it");
jNode.click()
}
function hrefClick(jNode) {
//alert("I am going to click it");
window.location = jNode.attr('href')
}
// Function to process and click on an element with detailed logging
function processAndClickElement(jqElement, description = "element") {
try {
// Convert jQuery element to DOM element if needed
const element = jqElement instanceof jQuery ? jqElement[0] : jqElement;
if (!element) {
log('Error: Element is null or undefined', true);
return false;
}
log(`Found ${description}`, false);
// Get element details for debugging
const elementDetails = {
text: safeGetText(element).trim(),
href: element.tagName && element.tagName.toLowerCase() === 'a' ? (safeGetAttribute(element, 'href') || 'none') : 'n/a',
id: element.id || 'none',
classes: element.className || 'none',
tagName: element.tagName || 'unknown'
};
log(`${description} details: ${JSON.stringify(elementDetails)}`, false);
// Small delay before clicking
setTimeout(() => {
advancedClick(element);
}, 500);
return true;
} catch (error) {
log(`Error processing ${description}: ${error.message}`, true);
return false;
}
}
function getRemoteTriggerMacroUrl(macroUUID, compUUID, ...args) {
var argValue = Array.prototype.join.call(args, ',');
return `https://trigger.keyboardmaestro.com/t/${compUUID}/${macroUUID}?${argValue}`;
}
function getPublicWebMacroUrl(uuid, ...args) {
var argValue = Array.prototype.join.call(args, ',');
console.log(`********** argValue: ${argValue} `);
return `https://localhost:4491/action.html?macro=${uuid}&value=${argValue}`;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment