diff --git a/background.js b/background.js index e3e044c..7824a56 100644 --- a/background.js +++ b/background.js @@ -1,5 +1,5 @@ window.dark_object = { - + all_levels: { install: function() { { // Any level protected proptotypes @@ -8,7 +8,7 @@ window.dark_object = { // Very special functions String.prototype.hashCode = function(under = 100, over = 0) { var hash = 0, - i, chr; + i, chr; if (this.length === 0) return hash; for (i = 0; i < this.length; i++) { chr = this.charCodeAt(i); @@ -23,7 +23,7 @@ window.dark_object = { return hash; }; } - + const CSS_COLOR_NAMES = ["AliceBlue", "AntiqueWhite", "Aqua", "Aquamarine", "Azure", "Beige", "Bisque", "Black", "BlanchedAlmond", "Blue", "BlueViolet", "Brown", "BurlyWood", "CadetBlue", "Chartreuse", "Chocolate", "Coral", "CornflowerBlue", "Cornsilk", "Crimson", "Cyan", "DarkBlue", "DarkCyan", "DarkGoldenRod", "DarkGray", "DarkGrey", "DarkGreen", "DarkKhaki", "DarkMagenta", "DarkOliveGreen", "DarkOrange", "DarkOrchid", "DarkRed", "DarkSalmon", "DarkSeaGreen", "DarkSlateBlue", "DarkSlateGray", "DarkSlateGrey", "DarkTurquoise", "DarkViolet", "DeepPink", "DeepSkyBlue", "DimGray", "DimGrey", "DodgerBlue", "FireBrick", "FloralWhite", "ForestGreen", "Fuchsia", "Gainsboro", "GhostWhite", "Gold", "GoldenRod", "Gray", "Grey", "Green", "GreenYellow", "HoneyDew", "HotPink", "IndianRed", "Indigo", "Ivory", "Khaki", "Lavender", "LavenderBlush", "LawnGreen", "LemonChiffon", "LightBlue", "LightCoral", "LightCyan", "LightGoldenRodYellow", "LightGray", "LightGrey", "LightGreen", "LightPink", "LightSalmon", "LightSeaGreen", "LightSkyBlue", "LightSlateGray", "LightSlateGrey", "LightSteelBlue", "LightYellow", "Lime", "LimeGreen", "Linen", "Magenta", "Maroon", "MediumAquaMarine", "MediumBlue", "MediumOrchid", "MediumPurple", "MediumSeaGreen", "MediumSlateBlue", "MediumSpringGreen", "MediumTurquoise", "MediumVioletRed", "MidnightBlue", "MintCream", "MistyRose", "Moccasin", "NavajoWhite", "Navy", "OldLace", "Olive", "OliveDrab", "Orange", "OrangeRed", "Orchid", "PaleGoldenRod", "PaleGreen", "PaleTurquoise", "PaleVioletRed", "PapayaWhip", "PeachPuff", "Peru", "Pink", "Plum", "PowderBlue", "Purple", "RebeccaPurple", "Red", "RosyBrown", "RoyalBlue", "SaddleBrown", "Salmon", "SandyBrown", "SeaGreen", "SeaShell", "Sienna", "Silver", "SkyBlue", "SlateBlue", "SlateGray", "SlateGrey", "Snow", "SpringGreen", "SteelBlue", "Tan", "Teal", "Thistle", "Tomato", "Turquoise", "Violet", "Wheat", "White", "WhiteSmoke", "Yellow", "YellowGreen"] window.uDark = { rgb_a_colorsRegex: /rgba?\([%0-9., \/a-z_+*-]+\)/gmi, // rgba vals with variables names and calcs involved NOTE: #rgba(255 255 255 / 0.1) is valid color rgba(255,255,255,30%) is valid color too @@ -46,7 +46,7 @@ window.dark_object = { min_bright_bg_trigger: 0.2, // backgrounds with luminace under this value will remain as is min_bright_bg: 0.1, // background with value over min_bright_bg_trigger will be darkened from this value up to max_bright_bg max_bright_bg: 0.4, // background with value over min_bright_bg_trigger will be darkened from min_bright_bg up to this value - + str_protect: function(str, regexSearch, protectWith) { // sore values into an array: var values = str.match(regexSearch); @@ -59,11 +59,15 @@ window.dark_object = { protectWith }; }, - + str_unprotect: function(str, protection) { if (protection.values) { protection.values.forEach((value, index) => { - str = str.replace(protection.protectWith, value); + // I've learnt the hard way tto care about some $' or $1 the protected value: + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#specifying_a_string_as_the_replacement + // This is why we use a function to replace the protected value + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#specifying_a_function_as_the_replacement + str = str.replace(protection.protectWith, ()=>value); }) } return str; @@ -89,16 +93,21 @@ window.dark_object = { str_unprotect_numbered: function(str, protection, condition = true) { if (protection.values && condition) { protection.values.forEach((value, index) => { - str = str.replace(protection.protectWith.replace("{index}", index), value); + // I've learnt the hard way tto care about some $' or $1 the protected value: + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#specifying_a_string_as_the_replacement + // This is why we use a function to replace the protected value + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#specifying_a_function_as_the_replacement + + str = str.replace(protection.protectWith.replace("{index}", index), ()=>value); }) } return str; }, - + sRGBtoLin: (colorChannel) => { // Send this function a decimal sRGB gamma encoded color value // between 0.0 and 1.0, and it returns a linearized value. - + if (colorChannel <= 0.04045) { return colorChannel / 12.92; } else { @@ -114,7 +123,7 @@ window.dark_object = { YtoLstar: (Y) => { // Send this function a luminance value between 0.0 and 1.0, // and it returns L* which is "perceptual lightness" - + if (Y <= (216 / 24389)) { // The CIE standard states 0.008856 but 216/24389 is the intent for 0.008856451679036 return Y * (24389 / 27); // The CIE standard states 903.3, but 24389/27 is the intent, making 903.296296296296296 } else { @@ -140,24 +149,24 @@ window.dark_object = { }, duration) return interval_id; }, - + do_idk_mode: function() { let editableStyleSheets = [...document.wrappedJSObject.styleSheets].filter(styleSheet => { if (styleSheet.idk_mode_ok) { return false; // This one is still OK } styleSheet.idk_mode_ok = true; // This attribute is lost if the stylesheet is edited, so we can ignore this CSS. - + if (styleSheet.ownerNode.id == "UltimaDarkTempVariablesStyle") { return false; // Created on the document of the content script and becomes a cors stylesheet. It's already IDK resolved } if (styleSheet.href) { - + let styleSheetHref = (new URL(styleSheet.href)) let is_cross_domain = styleSheetHref.origin != document.location.origin; - + return !is_cross_domain && !uDark.chunk_stylesheets_idk_only_cors; // If it is cross domain, we will do it via a message to the background script - + } else if (styleSheet.ownerNode.classList.contains("ud-idk-vars")) { return true; } @@ -169,7 +178,7 @@ window.dark_object = { }); }, search_container_logo: function(element, notableInfos) { - + let parent = (element.parentNode || element) parent = (parent.parentNode || parent) return uDark.logo_match.test(parent.outerHTML + notableInfos.uDark_cssClass) @@ -181,11 +190,12 @@ window.dark_object = { { // Do not parse url preventing adding context to it or interpreting it as a relative url or correcting its content by any way let imageTrueSrc = src_override || image.getAttribute("src") - + if (uDark.userSettings.disable_image_edition || !imageTrueSrc) { + return imageTrueSrc; } - + if (!image.hasAttribute("data-ud-selector")) { image.setAttribute("data-ud-selector", Math.random()); } @@ -211,7 +221,7 @@ window.dark_object = { usedChar = "#"+usedChar; } imageTrueSrc = uDark.send_data_image_to_parser(imageTrueSrc, false, {...options, notableInfos, image}); - + return imageTrueSrc + usedChar + new URLSearchParams(notableInfos).toString(); }, valuePrototypeEditor: function(leType, atName, setter = x => x, conditon = false, aftermath = false,getter=false) { @@ -222,11 +232,11 @@ window.dark_object = { if (leType.concat) { return leType.forEach(aType => uDark.valuePrototypeEditor(aType, atName, setter, conditon, aftermath, getter)) } - + if (leType.wrappedJSObject) { // Cross compatibilty with content script leType = leType.wrappedJSObject; } - + var originalSet = Object.getOwnPropertyDescriptor(leType.prototype, atName); if (!originalSet) { console.log("No setter for '", atName, "'", leType, leType.name, leType.prototype) @@ -257,7 +267,7 @@ window.dark_object = { return getter(this, call_result); }, window); } - + // uDark.general_cache["o_ud_set_"+atName]=originalSet Object.defineProperty(leType.prototype, atName, override_get_set); }, @@ -288,7 +298,7 @@ window.dark_object = { // } leType.prototype.count=(leType.prototype.count||0)+1; if(!Object.getOwnPropertyDescriptor(leType.prototype, laFonction.name)) - { + { console.log("No getter for '", leType,laFonction,new Error(),leType.prototype.count,document.location.href) return; } @@ -314,7 +324,7 @@ window.dark_object = { } [laFonction.name] }); }, - + // At-rules : https://developer.mozilla.org/fr/docs/Web/CSS/At-rule // @charset, @import or @namespace, followed by some space or \n, followed by some content, followed by ; or end of STRING // Surpisingly and fortunately end of LINE does not delimits the end of the at-rule and forces devs & minifers either to add a ; or end of STRING @@ -325,29 +335,31 @@ window.dark_object = { // priority matches (\\\)) and (\\') and (\\") //-------------------v-Rule name----space or-CR--v-----v--Protected values-v----v-the content dot cssAtRulesRegex: /@(charset|import|namespace)(\n|\s)+((\((\\\)|.)+?\))|("(\\"|.)+?")|('(\\'|.)+?')|.)+?(;|$)/gs, - + edit_str_restore_imports_all_way: function(str, rules) { // This regexp seems a bit complex // because @import url("") can includes ";" which is also the css instruction separator like in following example // @charset "UTF-8";@import url("https://use.typekit.net/lls1fmf.css"); // @import url("https://fonts.googleapis.com/css2?family=Inter:wght@100;200;300;400;500;600;700;800;900&display=swap"); // .primary-1{ color: rgb(133, 175, 255); } - + // This code is sensible to some edge cases, like @rules put in a comment, or in a string, and this is why i removed comments before this call. // It was breaking https://www.pascalgamedevelopment.com/content.php . // It would be possible to fix this by adding a condition to the regex to avoid matching @rules in comments or strings, but it would be a bit more complex // Or even protecting the @rules individually wit a numbered css class, but it would be a bit more complex too regarding the occurences of the @rules in strings or comments - + let imports = str.match(uDark.cssAtRulesRegex) || []; rules.unshift(...imports); - + }, send_data_image_to_parser: function(str, details, options) { + // uDark..disable_data_image_edition=true; if (str.trim().toLowerCase().startsWith('data:') && !uDark.userSettings.disable_image_edition && !uDark.disable_data_image_edition) { let {b64,dataHeader,data,failure} = options.cut || uDark.decodeBase64DataURIifIsDataURI(str); - imageData = data; + let imageData = data; options.changed = true; + if (!failure && dataHeader.includes('svg')) // Synchronous edit for data SVGs images, we have some nice context and functions to work with { // This avoids loosing svg data including the size of the image, and the tags in the image uDark.disable_svg_data_url_edition = false; @@ -357,8 +369,17 @@ window.dark_object = { return str; } options.get_document=true; - - if(!b64){imageData=decodeURIComponent(imageData);} + + if(!b64){ + + // This replaces searche for unencoded % in image data, and replaces them by the equivalent %25. + // Some websites uses % in their svg data, while not encoding them. + // This results in a probalby broken image, since we are in a dataURL image. + // UltimaDark team dont care too much about this,but it can lead to decodeURI errors. and therefore to a broken page. + imageData=imageData.replace(/%(?![0-9a-z]{2})/gi,"%25") + imageData=decodeURIComponent(imageData); + } + imageData = uDark.frontEditHTML(false, imageData, details, options).body.innerHTML; let encoded=undefined; @@ -392,10 +413,12 @@ window.dark_object = { encoded=rencodeToURI(encoded, dataHeader.replace("base64",""), false); } - + } + str=encoded; } else { + str = "https://data-image?base64IMG=" + str; // Sending other images to the parser via the worker, if (options.image) { options.image.removeAttribute("crossorigin"); // data images are not CORS with this domain, so we remove the attribute to avoid CORS errors @@ -413,12 +436,12 @@ window.dark_object = { return fillValue } // fill has another meaning for animate let is_text = options.notableInfos.guessed_type == "logo" || ["text", "tspan"].includes(fillElem.tagName); - + if (!is_text && ["path"].includes(fillElem.tagName)) { let draw_path = fillElem.getAttribute("d"); // Lot of stop path in in path, it's probably a text is_text = draw_path && ([...draw_path.matchAll(/Z/ig)].length >= 2 || draw_path.length > 170) - + } fillElem.setAttribute("udark-edit", true); fillElem.setAttribute(class_name, `${options.notableInfos.guessed_type}${is_text?"-text":""}`); @@ -450,7 +473,7 @@ window.dark_object = { options.notableInfos.inside_clickable = true; } } - + if (!options.notableInfos.logo_match) { if (uDark.search_container_logo(svg, options.notableInfos)) { options.notableInfos.logo_match = true; @@ -459,23 +482,23 @@ window.dark_object = { if (options.notableInfos.logo_match || options.notableInfos.inside_clickable) { options.notableInfos.guessed_type = "logo"; } - + if (options.notableInfos.guessed_type == "logo") { - + svg.setAttribute("fill", "white"); // svg.removeAttribute("fill"); // svg.setAttribute("fill", "currentColor"); - + if (options.remoteSVG || options.svgDataImage) // If there is no style element, we don't need to create one { let styleElem = document.createElement("style"); styleElem.id = "udark-styled"; styleElem.append(document.createTextNode(uDark.inject_css_override)) styleElem.append(document.createTextNode("svg{color:white}")) // Allows "currentColor" to take effect - + svg.append(styleElem); } - + } svg.querySelectorAll("[fill]:not([udark-fill])").forEach(fillElem => { fillElem.setAttribute("fill", uDark.get_fill_for_svg_elem(fillElem, false, options)) @@ -484,40 +507,40 @@ window.dark_object = { fillElem.setAttribute("stroke", uDark.get_fill_for_svg_elem(fillElem, fillElem.getAttribute("stroke"), options).replace(/currentColor/i, "white"), "udark-stroke") }) // svg.querySelectorAll("circle").forEach(fillElem => { - // fillElem.setAttribute("ud-brightness-"+fillElem.outerHTML.hashCode(60,35), true); - + // fillElem.setAttribute("ud-brightness-"+fillElem.outerHTML.hashCode(60,35), true); + // fillElem.setAttribute("fill", "black"); // }) - + // let all_svg_elems=svg.querySelectorAll(":not(udark-edit)"); // all_svg_elems.forEach((fillElem,index) => { - // if(fillElem.hasAttribute("fill")){ + // if(fillElem.hasAttribute("fill")){ // return; // } // let is_text=uDark.get_fill_for_svg_elem(fillElem, false,{notableInfos:{}},class_name="udark-gradient",transform=false) // if(!is_text){ // fillElem.setAttribute("ud-brightness-"+Math.floor((uDark.min_bright_bg+(index/all_svg_elems.length))*100), true); // } - + // }); - + svg.setAttribute("udark-guess", options.notableInfos.guessed_type); svg.setAttribute("udark-infos", new URLSearchParams(options.notableInfos).toString()); - + }, edit_styles_attributes: function(parentElement, details, options = {}) { parentElement.querySelectorAll("[style]").forEach(astyle => { // console.log(details,astyle,astyle.innerHTML,astyle.innerHTML.includes(`button,[type="reset"],[type="button"],button:hover,[type="button"],[type="submit"],button:active:hover,[type="button"],[type="submi`)) astyle.setAttribute("style", uDark.edit_str(astyle.getAttribute("style"), false, false, details, false, options)); }); - + }, edit_styles_elements: function(parentElement, details, add_class = "ud-edited-background", options = {}) { parentElement.querySelectorAll(`style:not(.${add_class})`).forEach(astyle => { // if(Math.random()<0.2){ // console.log(astyle); // return; - + // } // if(astyle.innerHTML.includes("/*!sc*/")) // { @@ -538,21 +561,21 @@ window.dark_object = { }, frontEditHTML: function(elem, value, details, options = {}) { // 1. Ignore