Skip to content

Instantly share code, notes, and snippets.

@stefanseeger
Created October 8, 2024 08:20
Show Gist options
  • Save stefanseeger/42e1e47d0c975e2982acebdcb6ce367c to your computer and use it in GitHub Desktop.
Save stefanseeger/42e1e47d0c975e2982acebdcb6ce367c to your computer and use it in GitHub Desktop.
/** Utils to be used in the User-Scripts */
'use strict';
class TmUtils {
/** @returns `Promise` which resolves when ``HTMLElement` for selector was found */
async waitForElement(selector, base = document) {
return new Promise((resolve) => {
if (this.$(selector, base)) {
return resolve(this.$(selector));
}
const observer = new MutationObserver(() => {
if (this.$(selector, base)) {
resolve(this.$(selector, base));
observer.disconnect();
}
});
observer.observe(document.body, {
childList: true,
subtree: true,
});
});
}
/**
* Sets value for `HTMLInput` for selector
* @param force override previous value
*/
async setValue(selectorOrElement, value, base = document, force = false) {
const element = this.$(selectorOrElement, base);
// Only set value if not set already or disabled
if (
element &&
(force || !this.hasValue(element)) &&
!this.isTampermonkeyChange(element) &&
!this.isDisabled(element)
) {
this.setTampermonkeyChange(element);
element.value = value;
element.dispatchEvent(new Event('input'));
element.dispatchEvent(new Event('change'));
element.dispatchEvent(new Event('blur'));
}
}
/** @returns value of `HTMLInput` for selector */
getValue(selectorOrElement, base = document) {
const element = this.$(selectorOrElement, base);
return element?.value;
}
/** @returns `true` when `HTMLInput` for selector has a value. */
hasValue(selectorOrElement, base = document) {
const value = this.getValue(selectorOrElement, base);
return value !== '0: null' && value !== '1: undefined' && value;
}
/** Clicks `HTMLElement` for selector */
click(selectorOrElement, base = document) {
const element = this.$(selectorOrElement, base);
if (
element &&
!this.isTampermonkeyChange(element) &&
!this.isDisabled(element)
) {
this.setTampermonkeyChange(element);
element.click();
}
}
/** checks checkbox for selector */
check(selectorOrElement, value = true, base = document) {
const input = this.$(selectorOrElement, base);
if (
input &&
input.checked != value &&
!this.isTampermonkeyChange(input) &&
!this.isDisabled(input)
) {
this.setTampermonkeyChange(input);
input.click();
}
}
/**
* Selects `mat-option` in `mat-select`
* @param index of the option to select
*/
async matSelect(selector, base = document, index = 0) {
const matSelect = this.$(`mat-select${selector}.ng-pristine`, base);
if (matSelect) {
matSelect.click();
this.setTampermonkeyChange(matSelect);
await this.waitForElement('mat-option');
this.$$('mat-option')[index].click();
}
}
/**
* @returns first `HTMLELement` for the provided selector
* @param selectorOrElement will directly be returned if it is not a string. Otherwise `querySelector` is used.
*/
$(selectorOrElement, base = document) {
if (typeof selectorOrElement === 'string') {
return base.querySelector(selectorOrElement);
}
return selectorOrElement;
}
/** @returns all `HTMLElements` for the provided selector */
$$(selector, base = document) {
return base.querySelectorAll(selector);
}
/** @returns `true` when element is diabled */
isDisabled(selectorOrElement, base = document) {
const element = this.$(selectorOrElement, base);
return element?.disabled;
}
/** @returns date `string` for provided `Date` object */
dateString(date = new Date()) {
return (
'' +
(date.getDate() + '').padStart(2, 0) +
'.' +
(date.getMonth() + 1 + '').padStart(2, 0) +
'.' +
date.getFullYear()
);
}
/** @returns date `string` which is accepted by the email pattern for provided `Date` object */
emailFriendlyDate(date = new Date()) {
const year = this.dateString(date);
const time =
'' +
date.getHours() +
'-' +
date.getMinutes() +
'-' +
date.getSeconds();
return year + '_' + time;
}
/** Resolves Promise after given timeout */
async wait(timeout) {
if (!timeout) return;
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, timeout);
});
}
/** Searches for attribute which marks Tampermonkey changes */
isTampermonkeyChange(selectorOrElement, base) {
const element = this.$(selectorOrElement, base);
return !!element?.hasAttribute('data-tampermonkey');
}
// Set Tampermonkey change attribute
setTampermonkeyChange(selectorOrElement, base) {
const element = this.$(selectorOrElement, base);
element.setAttribute('data-tampermonkey', true);
}
/** Opens prompt to set a Tampermonkey value */
promptValue(text, variableName, defaultValue) {
let value = window.GM_getValue(variableName);
if (!value) {
value = prompt(text, defaultValue ?? '');
window.GM_setValue(variableName, value);
}
return value;
}
/** Checks URL for `resetTampermonkey=true` and resets all Tampermonkey values when found */
resetTampermonkey() {
if (window.location.href.includes('resetTampermonkey=true')) {
const keys = window.GM_listValues();
keys.forEach((key) => {
window.GM_deleteValue(key);
});
alert('Tampermonkey was resetted');
}
}
}
window.TM_Utils = new TmUtils();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment