* Fix Network configuration parameter * feat: allow for showing raw transaction hex for ETH transactions * chore: remove comments from JS code to avoid parsing issues in tests * temp: comment out failing tx template tests * chore: trim text from copyable before writing it to clipboard * chore: improve the design of Transaction hex * chore: add wrap to element showing raw hex data * fixup! chore: add wrap to element showing raw hex data * chore: remove redundant style, make HTML prettier * Revert "temp: comment out failing tx template tests" This reverts commit f104ebbf5111583b46996d7527a26c08cd9e29b6. * chore: put rawTx javascript functionality into main.js * chore: modify the expected HTML for changed tx template * feat: support the raw transaction hex also for BTC-like coins * chore: add on-hover effect for active button - make the background white * Minify javascript and styles --------- Co-authored-by: Martin Boehm <martin.boehm@1mbsoftware.net>
219 lines
6.3 KiB
JavaScript
219 lines
6.3 KiB
JavaScript
function syntaxHighlight(json) {
|
|
json = JSON.stringify(json, undefined, 2);
|
|
json = json
|
|
.replace(/&/g, "&")
|
|
.replace(/</g, "<")
|
|
.replace(/>/g, ">");
|
|
if (json.length > 1000000) {
|
|
return `<span class="key">${json}</span>`;
|
|
}
|
|
return json.replace(
|
|
/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g,
|
|
(match) => {
|
|
let cls = "number";
|
|
if (/^"/.test(match)) {
|
|
if (/:$/.test(match)) {
|
|
cls = "key";
|
|
} else {
|
|
cls = "string";
|
|
}
|
|
} else if (/true|false/.test(match)) {
|
|
cls = "boolean";
|
|
} else if (/null/.test(match)) {
|
|
cls = "null";
|
|
}
|
|
return `<span class="${cls}">${match}</span>`;
|
|
}
|
|
);
|
|
}
|
|
|
|
function getCoinCookie() {
|
|
if(hasSecondary) return document.cookie
|
|
.split("; ")
|
|
.find((row) => row.startsWith("secondary_coin="))
|
|
?.split("=");
|
|
}
|
|
|
|
function changeCSSStyle(selector, cssProp, cssVal) {
|
|
const mIndex = 1;
|
|
const cssRules = document.all ? "rules" : "cssRules";
|
|
for (
|
|
i = 0, len = document.styleSheets[mIndex][cssRules].length;
|
|
i < len;
|
|
i++
|
|
) {
|
|
if (document.styleSheets[mIndex][cssRules][i].selectorText === selector) {
|
|
document.styleSheets[mIndex][cssRules][i].style[cssProp] = cssVal;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
function amountTooltip() {
|
|
const prim = this.querySelector(".prim-amt");
|
|
const sec = this.querySelector(".sec-amt");
|
|
const csec = this.querySelector(".csec-amt");
|
|
const base = this.querySelector(".base-amt");
|
|
const cbase = this.querySelector(".cbase-amt");
|
|
let s = `${prim.outerHTML}<br>`;
|
|
if (base) {
|
|
let t = base.getAttribute("tm");
|
|
if (!t) {
|
|
t = "now";
|
|
}
|
|
s += `<span class="amt-time">${t}</span>${base.outerHTML}<br>`;
|
|
}
|
|
if (cbase) {
|
|
s += `<span class="amt-time">now</span>${cbase.outerHTML}<br>`;
|
|
}
|
|
if (sec) {
|
|
let t = sec.getAttribute("tm");
|
|
if (!t) {
|
|
t = "now";
|
|
}
|
|
s += `<span class="amt-time">${t}</span>${sec.outerHTML}<br>`;
|
|
}
|
|
if (csec) {
|
|
s += `<span class="amt-time">now</span>${csec.outerHTML}<br>`;
|
|
}
|
|
return `<span class="l-tooltip">${s}</span>`;
|
|
}
|
|
|
|
function addressAliasTooltip() {
|
|
const type = this.getAttribute("alias-type");
|
|
const address = this.getAttribute("cc");
|
|
return `<span class="l-tooltip">${type}<br>${address}</span>`;
|
|
}
|
|
|
|
function handleTxPage(rawData, txId) {
|
|
const rawOutput = document.getElementById('raw');
|
|
const rawButton = document.getElementById('raw-button');
|
|
const rawHexButton = document.getElementById('raw-hex-button');
|
|
|
|
rawOutput.innerHTML = syntaxHighlight(rawData);
|
|
|
|
let isShowingHexData = false;
|
|
|
|
const memoizedResponses = {};
|
|
|
|
async function getTransactionHex(txId) {
|
|
// BTC-like coins have a 'hex' field in the raw data
|
|
if (rawData['hex']) {
|
|
return rawData['hex'];
|
|
}
|
|
if (memoizedResponses[txId]) {
|
|
return memoizedResponses[txId];
|
|
}
|
|
const fetchedData = await fetchTransactionHex(txId);
|
|
memoizedResponses[txId] = fetchedData;
|
|
return fetchedData;
|
|
}
|
|
|
|
async function fetchTransactionHex(txId) {
|
|
const response = await fetch(`/api/rawtx/${txId}`);
|
|
if (!response.ok) {
|
|
throw new Error(`Error fetching data: ${response.status}`);
|
|
}
|
|
const txHex = await response.text();
|
|
const hexWithoutQuotes = txHex.replace(/"/g, '');
|
|
return hexWithoutQuotes;
|
|
}
|
|
|
|
function updateButtonStyles() {
|
|
if (isShowingHexData) {
|
|
rawButton.classList.add('active');
|
|
rawButton.style.fontWeight = 'normal';
|
|
rawHexButton.classList.remove('active');
|
|
rawHexButton.style.fontWeight = 'bold';
|
|
} else {
|
|
rawButton.classList.remove('active');
|
|
rawButton.style.fontWeight = 'bold';
|
|
rawHexButton.classList.add('active');
|
|
rawHexButton.style.fontWeight = 'normal';
|
|
}
|
|
}
|
|
|
|
updateButtonStyles();
|
|
|
|
rawHexButton.addEventListener('click', async () => {
|
|
if (!isShowingHexData) {
|
|
try {
|
|
const txHex = await getTransactionHex(txId);
|
|
rawOutput.textContent = txHex;
|
|
} catch (error) {
|
|
console.error('Error fetching raw transaction hex:', error);
|
|
rawOutput.textContent = `Error fetching raw transaction hex: ${error.message}`;
|
|
}
|
|
isShowingHexData = true;
|
|
updateButtonStyles();
|
|
}
|
|
});
|
|
|
|
rawButton.addEventListener('click', () => {
|
|
if (isShowingHexData) {
|
|
rawOutput.innerHTML = syntaxHighlight(rawData);
|
|
isShowingHexData = false;
|
|
updateButtonStyles();
|
|
}
|
|
});
|
|
}
|
|
|
|
window.addEventListener("DOMContentLoaded", () => {
|
|
const a = getCoinCookie();
|
|
if (a?.length === 3) {
|
|
if (a[2] === "true") {
|
|
changeCSSStyle(".prim-amt", "display", "none");
|
|
changeCSSStyle(".sec-amt", "display", "initial");
|
|
}
|
|
document
|
|
.querySelectorAll(".amt")
|
|
.forEach(
|
|
(e) => new bootstrap.Tooltip(e, { title: amountTooltip, html: true })
|
|
);
|
|
}
|
|
|
|
document
|
|
.querySelectorAll("[alias-type]")
|
|
.forEach(
|
|
(e) =>
|
|
new bootstrap.Tooltip(e, { title: addressAliasTooltip, html: true })
|
|
);
|
|
|
|
document
|
|
.querySelectorAll("[tt]")
|
|
.forEach((e) => new bootstrap.Tooltip(e, { title: e.getAttribute("tt") }));
|
|
|
|
document.querySelectorAll("#header .bb-group>.btn-check").forEach((e) =>
|
|
e.addEventListener("click", (e) => {
|
|
const a = getCoinCookie();
|
|
const sc = e.target.id === "secondary-coin";
|
|
if (a?.length === 3 && (a[2] === "true") !== sc) {
|
|
document.cookie = `${a[0]}=${a[1]}=${sc}; Path=/`;
|
|
changeCSSStyle(".prim-amt", "display", sc ? "none" : "initial");
|
|
changeCSSStyle(".sec-amt", "display", sc ? "initial" : "none");
|
|
}
|
|
})
|
|
);
|
|
|
|
document.querySelectorAll(".copyable").forEach((e) =>
|
|
e.addEventListener("click", (e) => {
|
|
if (e.clientX < e.target.getBoundingClientRect().x) {
|
|
let t = e.target.getAttribute("cc");
|
|
if (!t) t = e.target.innerText;
|
|
const textToCopy = t.trim();
|
|
navigator.clipboard.writeText(textToCopy);
|
|
e.target.className = e.target.className.replace("copyable", "copied");
|
|
setTimeout(
|
|
() =>
|
|
(e.target.className = e.target.className.replace(
|
|
"copied",
|
|
"copyable"
|
|
)),
|
|
1000
|
|
);
|
|
e.preventDefault();
|
|
}
|
|
})
|
|
);
|
|
});
|