Adds primary indicators to the OVTLYR 9
// ==UserScript==
// @name OVTLYR Indicators
// @description Adds primary indicators to the OVTLYR 9
// @run-at document-idle
// @include /^https?://(www\.)?ovtlyr\.com/dashboard/[a-zA-Z]+$/
// @grant none
// @license GPL
// @version 0.0.1.20250829074731
// @namespace https://greasyfork.org/users/1509889
// ==/UserScript==
(function() {
'use strict';
// Tooltip text for the indicators (you can edit these)
// Checks the browser's language to use "favourite" or "favorite"
const isAmericanEnglish = navigator.language === 'en-US';
const bftTooltipText = isAmericanEnglish ? "Batman's Favorite Trade" : "Batman's Favourite Trade";
const tbtTooltipText = "The Big Trend";
// Lists of box IDs for each indicator type
const bftBoxes = ['div_sectorFG', 'div_marketBreadth', 'div_stockTrend'];
const tbtBoxes = ['div_marketTrend', 'div_sectorBreadth', 'div_stockTrend'];
// A map of boxes and the indicator text they should have, along with their position
const indicatorsData = [{
id: 'div_sectorFG', text: 'BFT', right: '5px'
}, {
id: 'div_marketBreadth', text: 'BFT', right: '5px'
}, {
id: 'div_stockTrend', text: 'BFT', right: '5px'
}, {
id: 'div_marketTrend', text: 'TBT', left: '5px'
}, {
id: 'div_sectorBreadth', text: 'TBT', left: '5px'
}, {
id: 'div_stockTrend', text: 'TBT', left: '5px'
}];
// A single, reusable tooltip element for the entire page
let tooltip;
function createTooltip() {
tooltip = document.createElement('div');
tooltip.style.position = 'absolute';
tooltip.style.display = 'none';
tooltip.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
tooltip.style.color = 'white';
tooltip.style.padding = '5px 10px';
tooltip.style.borderRadius = '5px';
tooltip.style.zIndex = '9999';
tooltip.style.fontSize = '12px';
tooltip.style.whiteSpace = 'nowrap';
document.body.appendChild(tooltip);
}
function addIndicator(targetId, text, position) {
const targetBox = document.getElementById(targetId);
if (targetBox) {
if (targetBox.querySelector(`.indicator-${text}`)) {
return;
}
const indicator = document.createElement('span');
indicator.className = `indicator-${text}`;
indicator.style.position = 'absolute';
indicator.style.top = '5px';
indicator.style.padding = '2px 5px';
indicator.style.borderRadius = '5px';
indicator.style.color = '#FFFFFF';
indicator.style.fontSize = '10px';
indicator.style.fontWeight = 'bold';
indicator.textContent = text;
indicator.style.transition = 'background-color 0.5s ease-in-out, box-shadow 0.2s ease-in-out';
indicator.style.zIndex = '1';
indicator.style.cursor = 'pointer';
if (text === 'BFT') {
indicator.dataset.tooltipText = bftTooltipText;
} else if (text === 'TBT') {
indicator.dataset.tooltipText = tbtTooltipText;
}
if (position.right) {
indicator.style.right = position.right;
} else if (position.left) {
indicator.style.left = position.left;
}
const computedStyle = window.getComputedStyle(targetBox);
if (computedStyle.position === 'static') {
targetBox.style.position = 'relative';
}
targetBox.appendChild(indicator);
indicator.addEventListener('mouseenter', (event) => {
const rect = event.target.getBoundingClientRect();
tooltip.textContent = event.target.dataset.tooltipText;
tooltip.style.left = `${rect.left + window.scrollX}px`;
tooltip.style.top = `${rect.bottom + window.scrollY + 5}px`;
tooltip.style.display = 'block';
const indicatorType = event.target.textContent;
const allIndicators = document.querySelectorAll(`.indicator-${indicatorType}`);
allIndicators.forEach(el => {
el.style.boxShadow = '0 0 5px 2px #fff';
});
});
indicator.addEventListener('mouseleave', (event) => {
tooltip.style.display = 'none';
const indicatorType = event.target.textContent;
const allIndicators = document.querySelectorAll(`.indicator-${indicatorType}`);
allIndicators.forEach(el => {
el.style.boxShadow = 'none';
});
});
}
}
function updateAllIndicatorColors() {
const isBftPink = bftBoxes.some(id => {
const el = document.getElementById(id);
return el && el.classList.contains('pink_backg');
});
const bftColor = isBftPink ? '#FF0000' : '#008000';
const isTbtPink = tbtBoxes.some(id => {
const el = document.getElementById(id);
return el && el.classList.contains('pink_backg');
});
const tbtColor = isTbtPink ? '#FF0000' : '#008000';
indicatorsData.forEach(item => {
const box = document.getElementById(item.id);
if (box) {
const indicator = box.querySelector(`.indicator-${item.text}`);
if (indicator) {
if (item.text === 'BFT') {
indicator.style.backgroundColor = bftColor;
} else if (item.text === 'TBT') {
indicator.style.backgroundColor = tbtColor;
}
}
}
});
}
window.addEventListener('load', () => {
createTooltip();
const allUniqueBoxes = [...new Set([...bftBoxes, ...tbtBoxes])];
allUniqueBoxes.forEach(id => {
const targetNode = document.getElementById(id);
if (targetNode) {
indicatorsData.filter(item => item.id === id).forEach(item => {
if (item.right) {
addIndicator(item.id, item.text, { right: item.right });
} else if (item.left) {
addIndicator(item.id, item.text, { left: item.left });
}
});
const observer = new MutationObserver(updateAllIndicatorColors);
observer.observe(targetNode, {
attributes: true,
attributeFilter: ['class']
});
}
});
updateAllIndicatorColors();
});
})();