-1

I have a lot of colors on a site, which I want to change with an userscript. Imagine a CSS file with 1000 different selectors, where each has a color. That specific color is what I want to change. Every instance of that color. The user has to be able to change the color dynamically (like with an input box), so changing it with a CSS file will not work.

If it worked, then this would be how I would do it:

$("*").replace("#00aba0","#FF0000");

00aba0 is the color I want to replace with FF0000

Unfortunately that method is unavailable, but it would work something like that. Also, setting up a loop to do like string.replace(); isn't going to work, as it's a forum, and when you make a new reply, it will remove the text inside the reply box.

TO SUM UP:

I want to replace every instance of a color, with another color. There are many instances (let's say 500) of that color, which has to be changed. I cannot change it with a replacement of the CSS file, and it has to be changed dynamically.

MortenMoulder
  • 6,138
  • 11
  • 60
  • 116

4 Answers4

7

Based on your situation, here's what would be in your best interest.

Remove the color from all of your CSS classes, and delegate the color to a new, separate class, like so.

.header {position: relative; font-size:24px;}
.whatever {position: relative; float:right;}

.theme-default {color:#00aba0; background-color:#fff;}
.theme-highlight {color:#FF0000; background-color:#000;}

So, for all of your elements, use the following class attributes:

<div class="header theme-default">This is the header</div>
<div class="whatever theme-default">This is whatever</div>

Then, to change the theme instantaneously, use this jQuery:

$(".theme-default").addClass("theme-highlight");

Edit: Dynamic Color Changes from User Input

You specified that you wanted the new color determined by the user. Changing the color completely dynamically with user input can be tricky, but I've done some reading and I think it can be done.

Consider this demo.

$("#changeColor").on("click", function() {
    var newColor = $("#color").val();
    var oldColor = "#00aba0";
    $("*").css("color", function(i, val) {
        val = val.replace(/\s/g, "");
        if (val == oldColor || val == hexToRgb(oldColor)) {
            return newColor;
        }
        else {
            return val;
        }
    });
});

Looking at the script, you'll see that we use your original $("*") selector. We then use .css(), making the second argument a function that returns a new color attribute based on the current one.

The main obstacle here was that we need to compare each element's current CSS color to the one we're looking for. Different browsers return different values for $("element").css("color"), so in an attempt to normalize them, I used Tim Down's hexToRgb() function to make a comparable RGB value for each color.

In the fiddle, try changing the default colors around, both within the stylesheet and inline, and you'll see that the script still works. You'll have to expand on the script so that you can manipulate the oldColor variable and change the colors back if needed.

Hope this helps.

Community
  • 1
  • 1
theftprevention
  • 5,083
  • 3
  • 18
  • 31
  • So I would have to select 1000 classes/IDs? Yeah, that's not going to work, as I wrote in the OP. Thanks for your answer, though. – MortenMoulder Sep 17 '13 at 18:24
  • If you're using CSS properly, then no, you won't have to select 1000 classes. – theftprevention Sep 17 '13 at 18:26
  • Okay. I have 500 different IDs and 500 different classes. All with different names. Please don't tell me to select all 1000. – MortenMoulder Sep 17 '13 at 18:27
  • Okay, so you still want me to select every class and ID, then replace the CSS? Come on.. Your new edit is just a workaround of your original post. The method hasn't changed, yet it still requires a lot of work, which I could do. I'm positive there's an easier way. We're talking about a REPLACEMENT of 1 color. – MortenMoulder Sep 17 '13 at 18:34
  • Yes, but your **one color** is defined **separately** in 500 different classes and IDs. We're beyond the point where you can expect this to be easy. – theftprevention Sep 17 '13 at 18:35
  • My final suggestion is to **create a duplicate of your current stylesheet.** Use CTRL + H to search and replace all instances of the first color with the second. Upload it, and then exchange the stylesheets dynamically when the appropriate user input is received. – theftprevention Sep 17 '13 at 18:37
  • @Snorlax defining 1000 times same color in a CSS file, isn't it redundant? You should start refactoring your CSS rules... – A. Wolff Sep 17 '13 at 18:37
  • That would still not make each user able to change the color dynamically. Please read the WHOLE question before answering. – MortenMoulder Sep 17 '13 at 18:37
  • @A. Wolff Same goes to you. READ THE WHOLE QUESTION. I wrote it's for an userscript and for a forum. Do you expect me to send a message to the owner, and ask him to core edit his public forum, just so I can do some minor edits? – MortenMoulder Sep 17 '13 at 18:39
  • @Snorlax really i'm sorry, i didn't catch it, using userscript. Please accept my apologies, you right, i should better read question even question is not clear – A. Wolff Sep 17 '13 at 18:40
  • No problem. People only care about points, which affects the original post. This whole reply should be deleted, as it doesn't do what I want. I could do this myself, but it would take a long time. Which is why I'm looking for another method, as I wrote as well. – MortenMoulder Sep 17 '13 at 18:43
  • @Snorlax the first time you talked about userscript was 23min after posting your question, you can understand people was not really aware of what you were trying to do – A. Wolff Sep 17 '13 at 18:45
  • @A.Wolff: You need to get some glasses. Read the first line in the OP. It clearly says "USERSCRIPT" as the last word, in the first line. – MortenMoulder Sep 17 '13 at 18:47
  • 6
    Most of the people answering in the past few minutes didn't realize that you wanted the new color to be input from the user, because **your original question did not mention it.** Your original version said "from an userscript" [sic]. "Userscript" does not automatically translate to "user input." That doesn't tell us much. The fact that you're trying to do something with no easy solution doesn't mean everyone around you is incompetent. Please realize that you're receiving advice, **for free**, and that your frustration over the lack of an easy solution doesn't entitle you to be immature. – theftprevention Sep 17 '13 at 18:49
  • I'm sorry, Jacob. Why is user input relevant in this connection? User input or hardcoded into the source of the userscript doesn't matter. Or have I missed something in my many hours of experience? – MortenMoulder Sep 17 '13 at 18:51
  • Oh, and thanks for standing together and downvoting my question. Who's immature? Thanks for not reading my question, yet voting it down because you have no idea how to solve it. – MortenMoulder Sep 17 '13 at 18:54
  • 3
    User input is relevant because it's the reason you didn't agree with the answers you got. You edited your question, and then got angry at those who had responded to your original question, lashing out with impatience, entitlement, and a general refusal to say something that didn't accuse the entire community of incompetence or illiteracy. That's not how this community works. You ask a question. If people don't understand, you clarify. When people saw your lack of professionalism, they downvoted because this was [**no longer a good question.**](http://stackoverflow.com/help/how-to-ask) – theftprevention Sep 17 '13 at 19:00
  • How is it no longer a good question, when it hasn't been answered? It has been answered with something I already knew, and was written in the question. Yet it's being downvoted because.. you don't know the answer? Because apparently I'm immature? Yeah, I'm sure that's it. And again.. Why is user input relevant? User input or hard coded is no difference, when we're talking about user scripting. – MortenMoulder Sep 17 '13 at 19:02
  • I made another edit with a solution that I think will work, and included a demo. See if it works for you. – theftprevention Sep 17 '13 at 19:32
  • That could work. It looks pretty much like davidkonrad's answer below. How would you do this, but with the background color instead? If it was **background-color** or just **background** instead of **color:** – MortenMoulder Sep 17 '13 at 19:59
  • The same way; the only change you'd need to make is to replace `$("*").css("color"...` with `$("*").css("background-color"...`. – theftprevention Sep 17 '13 at 20:15
3

One possible way is to play with window.getComputedStyle. Eg :

  1. Get all the page elements
  2. iterate, get the computedStyle for each
  3. compare with the color we want to change / replace
  4. replace color if needed

There are problems, such as getComputedStyle holds rgb(r,g,b)-values. Here is a little demonstration of the idea :

Demo : http://jsfiddle.net/Sg36t/ - (updated)

some styling :

#div1 {
 color: #ff0000; /* red in hex*/
}
#div2 {
  color : red;
}
h3#ah3 {
  color: green;
  background-color: red;
} 

test markup

<div id="div1">test</div>
<div id="div2">this is #div2
  <h3 id="ah3">text</h3>
</div>
<button id="test">change color</button>

script

function colorToHex(color) {
    if (color.substr(0, 1) === '#') {
        return color;
    }
    var digits = /(.*?)rgb\((\d+), (\d+), (\d+)\)/.exec(color);
    var red = parseInt(digits[2]);
    var green = parseInt(digits[3]);
    var blue = parseInt(digits[4]);
    var rgb = blue | (green << 8) | (red << 16);
    return digits[1] + '#' + rgb.toString(16);
};

function changeColor(from, to) {
   var elements = document.getElementsByTagName('*');
   for (var i=0;i<elements.length;i++) {
      var color = window.getComputedStyle(elements[i]).color;
      var hex = colorToHex(color);
      if (hex == from) {
         elements[i].style.color=to;
      }
      var backgroundColor = window.getComputedStyle(elements[i]).backgroundColor;
      if (backgroundColor.indexOf('rgba')<0) {
          var hex = colorToHex(backgroundColor);
          if (hex == from) {
             elements[i].style.backgroundColor=to;
          }
      }

   }
}   

// change all red color styled elements to blue
document.getElementById('test').onclick = function() {
   changeColor('#ff0000','#0000ff');
}

surprisingly, red-colored items, regardless red or #ff0000, is now turned into #0000ff...

NOTE : This is not meant as a final answer, or anything like that! But I feel this is a step in the right direction. At least it is an idea :)

davidkonrad
  • 83,997
  • 17
  • 205
  • 265
  • That's quite smart. However, I'm having a hard time trying to retreive the color from the background... – MortenMoulder Sep 17 '13 at 19:45
  • Updated to include backgroundColor. Update the [fiddle](http://jsfiddle.net/Sg36t/) aswell. But as I said, there are probably many issues. Undefined / not set backgrounds appearently turns out as `rgba()`, so then we have to consider this. I just ignore them, if a rgb-color background-color is set, then that will be changed also. – davidkonrad Sep 17 '13 at 20:03
  • Works perfectly. What if it has !important? – MortenMoulder Sep 17 '13 at 20:25
  • Have you tried? An educated guess is "nothing but the expected", eg !important are just forcing something to the CSS, there should not be any difference. – davidkonrad Sep 17 '13 at 21:04
  • Well when I try the script, it won't apply to properties with !important on. Only the non-important ones. – MortenMoulder Sep 19 '13 at 07:48
0
  1. Make a copy of that CSS file into a new one.
  2. Do a global find/replace of old color to new one.
  3. Replace reference to old stylesheet with new one
Yuriy Galanter
  • 38,833
  • 15
  • 69
  • 136
  • How would I change the color dynamically then? With an user input. – MortenMoulder Sep 17 '13 at 18:36
  • Can you please describe complete scenario then? It's still vague. Like 1. User enters color in Reply Box? 2. That color applies to the forum? Please be specific – Yuriy Galanter Sep 17 '13 at 18:39
  • @YuriyGalanter is talking about userscript even his question is not tagged as it... – A. Wolff Sep 17 '13 at 18:42
  • @A Wolff: Do I need to tag every aspect of my question. Okay, I will start now from HTML to Internet. Be right back.. @Yuriy: An user enters a color into a box (or chooses from a color picker), and then that color will replace every instance of a pre-coded color, which is #00aba0 in this example. – MortenMoulder Sep 17 '13 at 18:45
  • @Snorlax don't be so harsh but userscript change absolutely everything to your situation, you don't have access to original CSS file. Can you understand it??? – A. Wolff Sep 17 '13 at 18:47
  • 3
    @Snorlax good luck finding an answer with such attitude. You don't explain problem, you snap and those trying to help you - again, good luck. You will need it. – Yuriy Galanter Sep 17 '13 at 18:48
  • If people knew how to read, I would be more calm. Not a single person has done what I asked for, which pisses me off. If you don't know the answer, then don't post. Simple as that. Read, understand, post. Not "skim, not quite sure if understand, post". – MortenMoulder Sep 17 '13 at 18:49
  • 2
    @Snorlax You should add the step-by-step scenario to your question. It will save a lot of grief for you and those who read it. – Yuriy Galanter Sep 17 '13 at 18:53
0

Trying to change the color "of every instance" is not going to work well and is not the smart approach if those colors are set in a CSS file.

Your userscript can add stylesheets dynamically using GM_addStyle(), which is supported by all the major userscript platforms (and easy to backfill if it isn't).

Since the script's stylesheet(s) will usually be added after the target page's sheets, it will naturally override most rules. But use the !important flag to also overrule almost all inline style attributes.

In the handler for your user's color input, place code like so:

GM_addStyle ( "                                         \
    #node_X {                                           \
        background-color: " + usrColor + " !important;  \
    }                                                   \
    p.whatever {                                        \
        color: " + usrColor + " !important;             \
    }                                                   \
    /* etc. etc. */                                     \
" );

where usrColor is the variable with the user-set value.


Don't forget to specify @grant GM_addStyle in the script's metadata block.

This approach is "Fire and forget" and the new rules automatically apply to all new AJAXed content. The only thing it will not catch is if the target page uses style attributes that contain the !important flag. (which I have never seen a working site do)

Brock Adams
  • 90,639
  • 22
  • 233
  • 295