+
+
-
+
- // PROCESS A BLOCK/KERNEL SEARCH REQUEST
- function submitSearch() {
- // Get search string
- let query = document.getElementById("SearchField").value;
- // Simplistic test to check if search string is rather block height or kernel id
- let key = (query.length < 10) ? "&id=" : "&kernel=";
- // Load the corresponding URL
- window.location.href = UrlSelf("block", key + query);
- }
-
- // ADD EXPAND OPTIONS TO ALL TEXT OF TYPE HASH OR METADATA (CSS WILL DISPLAYED THEM TRUNCATED BY DEFAULT)
- function addExpandOptions() {
- // Text of type Hash (truncated/expanded)
- for (let myHash of document.querySelectorAll(".cid, .kernelId, .blob, .commitment")) {
- // Check if the text contains a link
- let myClass = (myHash.querySelector("a")) ? "truncated withLink" : "truncated";
- // Add a span to truncate the text, and another span to hold the clickable symbol
- let myHTML = myHash.innerHTML;
- myHash.innerHTML = "" + myHTML + "";
- // Add event listener on the symbol
- myHash.querySelector(".expand").addEventListener("click", expandHash);
- }
- // Text of type Metadata (reduced/full)
- for (let myMetadata of document.querySelectorAll(".metadata")) {
- // Add a span to truncate the text, and another span to hold the clickable symbol
- let myHTML = myMetadata.innerHTML;
- myMetadata.innerHTML = "" + myHTML + "";
- // Add event listener on the symbol
- myMetadata.querySelector(".extend").addEventListener("click", expandMetadata);
- }
- }
-
- function expandHash(e) {
- // Get element, table and column number of the event
- let input = e.currentTarget;
- // If item is in table, expand the whole column
- if (input.closest('table')) {
- let col = input.closest('th,td').cellIndex;
- let table = input.closest('table');
- // Loop on all cells in that column
- for (let myRow of table.rows) {
- // Remove all truncated classes in the cell
- for (let myItem of myRow.cells[col].querySelectorAll(".truncated")) {
- myItem.classList.remove("truncated");
- myItem.classList.add("expanded");
- // Switch action of the clickable symbols
- myItem.nextElementSibling.removeEventListener("click", expandHash);
- myItem.nextElementSibling.addEventListener("click", truncateHash);
- }
- }
- } else {
- // Expand only the item and its siblings
- for (let myItem of input.parentNode.querySelectorAll(".truncated")) {
- myItem.classList.remove("truncated");
- myItem.classList.add("expanded");
- // Switch action of the clickable symbols
- myItem.nextElementSibling.removeEventListener("click", expandHash);
- myItem.nextElementSibling.addEventListener("click", truncateHash);
- }
- }
- }
-
- function truncateHash(e) {
- // Get element, table and column number of the event
- let input = e.currentTarget;
- // If item is in table, truncate the whole column
- if (input.closest('table')) {
- let col = input.closest('th,td').cellIndex;
- let table = input.closest('table');
- // Loop on all cells in that column
- for (let myRow of table.rows) {
- // Remove all expanded classes in the cell
- for (let myItem of myRow.cells[col].querySelectorAll(".expanded")) {
- myItem.classList.remove("expanded");
- myItem.classList.add("truncated");
- // Switch action of the clickable symbols
- myItem.nextElementSibling.removeEventListener("click", truncateHash);
- myItem.nextElementSibling.addEventListener("click", expandHash);
- }
- }
- } else {
- // Expand only the item and its siblings
- for (let myItem of input.parentNode.querySelectorAll(".expanded")) {
- myItem.classList.remove("expanded");
- myItem.classList.add("truncated");
- // Switch action of the clickable symbols
- myItem.nextElementSibling.removeEventListener("click", truncateHash);
- myItem.nextElementSibling.addEventListener("click", expandHash);
- }
- }
- }
-
- function expandMetadata(e) {
- // Expand selected metadata only
- let input = e.currentTarget;
- for (let myItem of input.parentNode.querySelectorAll(".reduced")) {
- myItem.classList.remove("reduced");
- myItem.classList.add("full");
- // Switch action of the clickable symbols
- myItem.nextElementSibling.removeEventListener("click", expandMetadata);
- myItem.nextElementSibling.addEventListener("click", truncateMetadata);
- }
- }
-
- function truncateMetadata(e) {
- // Truncate selected metadata only
- let input = e.currentTarget;
- for (let myItem of input.parentNode.querySelectorAll(".full")) {
- myItem.classList.remove("full");
- myItem.classList.add("reduced");
- // Switch action of the clickable symbols
- myItem.nextElementSibling.removeEventListener("click", truncateMetadata);
- myItem.nextElementSibling.addEventListener("click", expandMetadata);
- }
- }
-
- function expandEverything() {
- // Expand all truncated Hashes
- for (let myItem of document.querySelectorAll(".truncated")) {
- myItem.classList.remove("truncated");
- myItem.classList.add("expanded");
- // Switch action of the clickable symbols
- myItem.nextElementSibling.removeEventListener("click", expandHash);
- myItem.nextElementSibling.addEventListener("click", truncateHash);
- }
- // Expand all truncated Metadata
- for (let myItem of document.querySelectorAll(".reduced")) {
- myItem.classList.remove("reduced");
- myItem.classList.add("full");
- // Switch action of the clickable symbols
- myItem.nextElementSibling.removeEventListener("click", expandMetadata);
- myItem.nextElementSibling.addEventListener("click", truncateMetadata);
- }
- // Expand all small collapsible blocks
- for (let myItem of document.querySelectorAll(".collapsible-checkbox")) {
- if (myItem.nextElementSibling.classList.contains("small")) {
- myItem.checked = true;
- }
- }
- // Switch action of the main clickable symbol
- let icon = document.querySelector("#ExpandAll");
- icon.setAttribute("href", "javascript:truncateEverything();");
- icon.setAttribute("title", "Collapse everything");
- }
-
- function truncateEverything() {
- // Truncate all Hashes
- for (let myItem of document.querySelectorAll(".expanded")) {
- myItem.classList.remove("expanded");
- myItem.classList.add("truncated");
- // Switch action of the clickable symbols
- myItem.nextElementSibling.removeEventListener("click", truncateHash);
- myItem.nextElementSibling.addEventListener("click", expandHash);
- }
- // Truncate all Metadata
- for (let myItem of document.querySelectorAll(".full")) {
- myItem.classList.remove("full");
- myItem.classList.add("reduced");
- // Switch action of the clickable symbols
- myItem.nextElementSibling.removeEventListener("click", truncateMetadata);
- myItem.nextElementSibling.addEventListener("click", expandMetadata);
- }
- // Collapse all small collapsible blocks
- for (let myItem of document.querySelectorAll(".collapsible-checkbox")) {
- if (myItem.nextElementSibling.classList.contains("small")) {
- myItem.checked = false;
- }
- }
- // Switch action of the main clickable symbol
- let icon = document.querySelector("#ExpandAll");
- icon.setAttribute("href", "javascript:expandEverything();");
- icon.setAttribute("title", "Expand everything");
- }
-
- // ALLOW ADDING FILTERS TO FIRST ROW OF ALL LONG TABLES
- function addFilterOption() {
- for (let myTable of document.getElementsByTagName("table")) {
- // Ignore tables of certain specific classes
- if (!myTable.classList.contains("tableTotals") && !myTable.classList.contains("tableSummary") && !myTable.closest('.divTableStatus')) {
- let myRow = myTable.rows[0];
- // If all cells of the first row are
or have a span with a "th" class, then mark the row as header.
- // We also enforce the use of to ensure that the row won't be included in the tbodies that will be filtered and sorted.
- // And since Chrome 83 (as in Beam Wallet) can only do 'sticky' on 'th' elements, we also change all its 'td' into 'th'.
- if ((myRow.querySelectorAll("td > span.th").length + myRow.querySelectorAll("th").length) == myRow.cells.length) {
- // If that first row is not already inside a thead (which means it's implicitely inside a tbody), then create a thead and move the row inside it.
- if (myRow.parentNode.nodeName != "THEAD") {
- let myTHead = myTable.createTHead();
- myTHead.appendChild(myRow);
- }
- // Mark the row as header
- myRow.classList.add("headerRow");
- // Define all cells in this first row as 'th' (remark: any attribute of those cells are lost, but we don't care)
- for (let myTd of myRow.cells) {
- let myTh = document.createElement("th");
- myTh.innerHTML = myTd.innerHTML;
- myTd.replaceWith(myTh);
- }
- // Add filters only to tables with more than a 5 lines
- if (myTable.rows.length > 5) {
- myRow.classList.add("filtersOff");
- myRow.addEventListener("click", addSortAndSearch);
- myRow.title = "Click to activate filters"; // This is for the tooltip
- } else {
- myRow.classList.add("filtersNot");
- }
- }
- }
- }
- }
-
- // ADD SORT AND SEARCH FILTERS TO FIRST ROW OF A GIVEN TABLE
- function addSortAndSearch(e)
- {
- // Get element of the event (the first row)
- let myRow = e.currentTarget;
-
- // Replace previous class and remove event and title (tooltip)
- myRow.classList.remove("filtersOff");
- myRow.classList.add("filtersOn");
- myRow.removeEventListener("click", addSortAndSearch);
- myRow.removeAttribute("title");
-
- // Apply to each cell of the first row (whether 'th' or 'td', it doesn't matter)
- for (let myHeader of myRow.cells) {
- // Wrap each header text into a div (will be clickable for sorting),
- // and then add a search input field below it.
- let myHTML = myHeader.innerHTML;
- myHeader.innerHTML = "\
-
\n\
-
" + myHTML + "
\n\
- \n\
-
\n";
- // Add event listeners to all elements
- myHeader.querySelector(".sortable").addEventListener("click", sortTable);
- myHeader.querySelector(".search").addEventListener("keyup", filterTable);
- }
- }
-
- // SORT ROWS BY CLICKING ON HEADERS (first ascending, then descending)
- function sortTable(e) {
- // Declare variables
- let input, col, headRow, table, nbr_tbodies, dir, items, switching, i, x, y, xVal, yVal, shouldSwitch, switchcount = 0;
-
- // Get element, table and column number of the event
- input = e.currentTarget;
- col = input.closest('th,td').cellIndex;
- headRow = input.closest('tr');
- table = input.closest('table');
- nbr_tbodies = table.tBodies.length;
-
- // Set the default sorting direction as descending
- // (or switch to ascending if already sorted descending)
- dir = (input.classList.contains("desc")) ? "asc" : "desc";
-
- // Reset sorting classes and titles in all headers of this table
- for (let myHeader of headRow.getElementsByClassName("sortable")) {
- myHeader.classList.remove("asc");
- myHeader.classList.remove("desc");
- myHeader.title = "Sort column";
- }
-
- // Get the list of rows or tbodies to be sorted
- // (Remark: There is always at least one tbody, even if not explictely defined)
- items = (nbr_tbodies > 1) ? table.tBodies : table.tBodies[0].rows;
- // Make an array with the items to be sorted
- let itemsArray = Array.from(items);
-
- // Make an array from the content of the cells in the selected column
- let colArray = itemsArray.map(function(item, index) {
- // Get the content of the cell in the column being sorted
- // (for tbodies with multiple lines, we concatenate the content of their cells in that column)
- let val = "";
- let myCell;
- if (nbr_tbodies > 1) {
- // Loop on all rows of the tbody
- for (let trow of item.rows) {
- // Concatenate content of each cell
- if (val != "") {val += "\n"};
- val += trow.cells[col].innerText;
- }
- } else {
- // Get content of the cell
- val = item.cells[col].innerText;
- }
- // Remove comas (just for numbers to be recognized as such).
- // And add its initial index (it will allow reordering the actual table rows or tbodies).
- let valArray = [val.replace(/,/g,''), index];
- return valArray;
- });
-
- // We initialise two collators for sorting:
- // One for "alphabetical sorting" (character by character, insensitive to case and accents).
- // One for "natural sorting" (same, except numbers are treated numerically: "Asset-1" < "Asset-2" < "Asset-10").
- let collator1 = Intl.Collator("en-US", {numeric: false, sensitivity: "base", usage: "sort", ignorePunctuation: "false"});
- let collator2 = Intl.Collator("en-US", {numeric: true, sensitivity: "base", usage: "sort", ignorePunctuation: "false"});
-
- // Sort the array (in ascending order by default)
- colArray.sort(function([a,b],[c,d]) {
- // Compare as numbers
- if (!isNaN(a) && !isNaN(c)) {return a - c}
- // Compare as address
- else if (/^[a-fA-F0-9]*$/.test(a) && /^[a-fA-F0-9]*$/.test(c)) {return collator1.compare(a,c)}
- // Compare as other strings
- else {return collator2.compare(a,c)}
- });
- // Reverse the array for descending order
- if (dir == "desc") {colArray.reverse();}
-
- // Get the 'parent' of the sorted items (i.e. the tbody in the case of rows, or the table in the case of tbodies)
- // Remark: The parent of a row is always a tbody, even if not explictely defined.
- let parent = items[0].parentNode;
- // Loop through the array of sorted cells to reorder the table rows or tbodies
- for (let sortedCol of colArray) {
- // Move each corresponding row or tbody to the end of the table.
- parent.appendChild(itemsArray[sortedCol[1]]);
- }
-
- // Update class and title in header by adding the sorting direction
- input.classList.add(dir);
- input.title = (dir == "desc") ? "Sort ascending" : "Sort descending";
- }
-
- // FILTER ROWS (OR GROUPS OF ROWS)
- function filterTable(e) {
- // Declare variables
- let table, tbodies, rows, trows, headers, input, filter, i, ii, j, k, td, txtValue, status;
-
- // Get tbodies and rows
- table = e.currentTarget.closest('table');
- tbodies = table.tBodies;
- rows = table.rows;
- headers = rows[0].cells;
-
- // If multiple tbodies are present, filtering will be done by tbodies instead of rows
- // (the inner rows in each tbody thus always being kept together)
-
- // Initialize results arrays with all 1 (i.e. all rows or tbodies are visible)
- let results_tbodies = new Array(tbodies.length).fill(1);
- let results_rows = new Array(rows.length).fill(1);
-
- // Always check again all header cells (so that filters on multiple columns can be combined!)
- for (j = 0; j < (headers.length); j++) {
- // Get search input field
- input = headers[j].querySelector(".search");
- // Get search query (we use toUpperCase() to perform a case-insensitive search)
- filter = input.value.toUpperCase();
- // Apply search query only if it's non-empty
- if (filter != "") {
- // Loop on all rows within all tbodies
- for (k = 0; k < (tbodies.length); k++) {
- // Only test cells if the tbody is not already marked as hidden
- if (results_tbodies[k] != 0) {
- // In case of multiple tbodies, start by hidding the tbody
- // (it will be displayed back if at least one of its rows matches the search query)
- if (tbodies.length > 1) { results_tbodies[k] = 0 }
- // Loop on all rows of the tbody
- trows = tbodies[k].rows;
- for (i = 0; i < (trows.length); i++) {
- // Get the overall index of the row in the table (independent of tbodies)
- // Remark: i and ii will be equal in the case of one single tbody
- ii = trows[i].rowIndex;
- // Only test the cell if the row is not already marked as hidden
- if (results_rows[ii] != 0) {
- // Get cell
- td = trows[i].cells[j];
- if (td) {
- // Get cell content
- txtValue = td.textContent || td.innerText;
- // If there are multiple tbodies, then filter by tbodies
- if (tbodies.length > 1) {
- // Mark tbody back as visible as soon as one of its rows matches
- // (and then stop looping on its rows)
- if (txtValue.toUpperCase().indexOf(filter) != -1) {
- results_tbodies[k] = 1;
- break;
- }
- // If there is only one tbody, then filter by rows
- } else {
- // Hide row if there is no match
- if (txtValue.toUpperCase().indexOf(filter) == -1) {
- results_rows[ii] = 0;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- // Special hack to avoid a display bug on Chrome 83 (when used as Beam Wallet DApp):
- // If a tbody is hidden, then each of its rows must also be hidden!
- if (tbodies.length > 1) {
- // Loop on all tbodies
- for (k = 0; k < (tbodies.length); k++) {
- // Loop on all rows of the tbody
- trows = tbodies[k].rows;
- for (i = 0; i < (trows.length); i++) {
- // Get the overall index of the row in the table (independent of tbodies)
- ii = trows[i].rowIndex;
- // Set status of the row identical to the tbody it belongs to
- results_rows[ii] = results_tbodies[k];
- }
- }
- }
- // Apply final results by setting the visibility of all tbodies and rows
- for (k = 0; k < (tbodies.length); k++) {
- status = (results_tbodies[k] == 0) ? "collapse" : "visible";
- tbodies[k].style.visibility = status;
- }
- for (ii = 1; ii < (rows.length); ii++) {
- status = (results_rows[ii] == 0) ? "collapse" : "visible";
- rows[ii].style.visibility = status;
- }
- }
-
- // SCROLL DOWN TO BOTTOM OR BACK TO TOP
- window.onscroll = function() {scrollFunction()};
- // When the user scrolls away 40px from top or bottom of the page, show the up or down buttons
- function scrollFunction() {
- let myTopButton = document.getElementById("TopButton");
- if (document.body.scrollTop > 40 || document.documentElement.scrollTop > 40) {
- myTopButton.style.display = "block";
- } else {
- myTopButton.style.display = "none";
- }
- let myBottomButton = document.getElementById("BottomButton");
- if (Math.abs(document.body.scrollHeight - document.body.scrollTop - document.body.clientHeight) > 40 || Math.abs(document.documentElement.scrollHeight - document.documentElement.scrollTop - document.documentElement.clientHeight) > 40) {
- myBottomButton.style.display = "block";
- } else {
- myBottomButton.style.display = "none";
- }
- }
- // Scroll to the top of the document
- function topFunction() {
- document.body.scrollTop = 0; // For Safari
- document.documentElement.scrollTop = 0; // For Chrome, Firefox, IE and Opera
- }
- // Scroll to the bottom of the document
- function bottomFunction() {
- document.body.scrollTop = Math.abs(document.body.scrollHeight - document.body.clientHeight); // For Safari
- document.documentElement.scrollTop = Math.abs(document.documentElement.scrollHeight - document.documentElement.clientHeight); // For Chrome, Firefox, IE and Opera
- }
-
- // TOGGLE DARK MODE
- function toggleDarkMode() {
- let mode = "";
- // For dark mode, we add a class to root
- let rootclass = document.querySelector(":root").classList;
- if ( rootclass.contains("dark") ) { rootclass.remove("dark") }
- else { rootclass.add("dark"); mode = "dark"; }
- // Store mode in localStorage (to allow retrieving it across pages)
- localStorage.setItem("mode", mode);
- }
-
+
+