NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name BambooSimplifyErrorFilter // @author ole.goebbels@dtn.com, after Profanity Filter by adisib (https://github.com/adisib/Profanity-Filter) // @namespace namespace_dtn // @description Simple filtering for ^error on Bamboo log website text to make searching for errors simpler. // @version 2020-08-11 // @license MIT // @include /.*bamboo.*\.log$/ // @grant none // ==/UserScript== (function() { "use strict"; // --- SETTINGS -------- // The string that replaces offending words. const replaceString = "stderr"; // Display performance and debugging information to the console. const DEBUG = false; // -------------------- let wordString = "^error"; const wordsFilter = new RegExp(wordString, "gm"); wordString = null; const findText = document.createExpression(".//text()[string-length() > 2 and not(parent::script or parent::code)]", null); // Initial slow filter pass that handles static text function filterStaticText() { let startTime, endTime; if (DEBUG) { startTime = performance.now(); } filterNodeTree(document.body); if (DEBUG) { endTime = performance.now(); console.log("PF | Static Text Run-Time (ms): " + (endTime - startTime).toString()); } } // -------------------- // filters dynamic text, and handles things such as AJAX Youtube comments function filterDynamicText() { let textMutationObserver = new MutationObserver(filterMutations); let TxMOInitOps = { characterData: true, childList: true, subtree: true }; textMutationObserver.observe(document.body, TxMOInitOps); } // -------------------- // Handler for mutation observer from filterDynamicText() function filterMutations(mutations) { let startTime, endTime; if (DEBUG) { startTime = performance.now(); } for (let i = 0; i < mutations.length; ++i) { let mutation = mutations[i]; if (mutation.type === "childList") { let nodes = mutation.addedNodes; for (let j = 0; j < nodes.length; ++j) { filterNodeTree(nodes[j]); } } else if (mutation.type === "characterData" && !mutation.target.parentNode.isContentEditable) { filterNode(mutation.target); } } if (DEBUG) { endTime = performance.now(); console.log("PF | Dynamic Text Run-Time (ms): " + (endTime - startTime).toString()); } } // -------------------- // Filters a textNode function filterNode(node) { if (DEBUG) { console.log(node.nodeName, node.nodeType); } if (wordsFilter.test(node.data)) { node.data = node.data.replace(wordsFilter, replaceString); } } // -------------------- // Filters all of the text from a node and its decendants function filterNodeTree(node) { if (!node || (node.nodeType !== Node.ELEMENT_NODE && node.nodeType !== Node.TEXT_NODE)) { return; } if (node.nodeType === Node.TEXT_NODE) { filterNode(node); return; // text nodes don't have children } let textNodes = findText.evaluate(node, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); const l = textNodes.snapshotLength; for (let i = 0; i < l; ++i) { filterNode(textNodes.snapshotItem(i)); } } // -------------------- // Runs the different filter types function filterPage() { filterStaticText(); filterDynamicText(); } // --- MAIN ----------- filterPage(); })();