bgrins / TinyColor

Fast, small color manipulation and conversion for JavaScript
https://bgrins.github.io/TinyColor/
MIT License
5.08k stars 438 forks source link

Option to restrict hex to require '#' char (or as validation option) #60

Closed andythenorth closed 10 years ago

andythenorth commented 10 years ago

This library is great, using it to validate and preview user-entered colors in a theming UI.

One issue I ran into:

A possible solution for me would be to post-process these when the form is saved. I'd prefer to restrict the input to valid values though. I had a read of TinyColor js to see if I had missed any obvious options for this, but didn't spot any.

Is there an option I'm missing? Or would you consider providing these, either for TinyColour object init, or for the isValid() function. NP if this is a weird use case and the answer is no. Workarounds would be found :)

-- EDIT -- I wrote additional validation using the private _format property of TinyColor object. Using the private var might break in future, but it was a lightweight solution that works nicely.

        var color_is_valid = false;
        if (color.isValid() == true) {
            if (color._format == 'hex') {
                if (input_value.charAt(0) == '#') {
                    color_is_valid = true;
                }
            } else if (color._format == 'rgb' || color._format == 'rgba') {
                if (input_value.charAt(input_value.length-1) == ')') {
                    color_is_valid = true;
                }
            } else {
                color_is_valid = true;
            }
        }
bgrins commented 10 years ago

Off the top of my head, I think this could be validated using the DOM before passing it into the tinycolor function. Maybe something like:

function isValidCSSColor(c) {
  var foo = document.createElement("div");
  foo.style.backgroundColor = c;
  return foo.style.backgroundColor !== "";
}

console.log(isValidCSSColor("red")); // true
console.log(isValidCSSColor("#f00")); // true
console.log(isValidCSSColor("f00")); // false

This would also handle cases like hsv or unparenthesized rgb, hsl and unsupported units.

bgrins commented 10 years ago

I'm not sure how well it would fit into the API, but it might be a handy utility to be able to:

var color = tinycolor("red");
color.isValidCSSColor()
andythenorth commented 10 years ago

isValidCSSColor() would work very well for the case I have, thanks. If it doesn't fit into the API, don't worry about it, the case I have is solved, just it's an ugly solution. :)

bgrins commented 10 years ago

The only issue with regards to the API is that it would rely on running in a browser environment, and it's supported in node

le717 commented 10 years ago

Doesn't this already exist?

console.log(tinycolor("fff").toHexString());

https://github.com/bgrins/TinyColor/blob/44ac02cb4a2c94f80d07dbceb83ee1b5cebeabcb/tinycolor.js#L105-L106

bgrins commented 10 years ago

@le717 I think the request is for that not to work. Basically, @teamrubberandy is wanting anything that isn't a valid css color to not parse (like "fff", "rgb 255 0 0", "hsv (0, 100%, 50%)", {r:1,g:1,b:1}, etc)

andythenorth commented 9 years ago

Yup, my aim is to validate user input, and fail if not valid css colors.

The generous parsing behaviour is neat, but the user input in my case is passed on as vars a less compile which then whines at me when it's invalid (or, in production, would blow up all over the user) :)

le717 commented 9 years ago

My question is this: are you, @teamrubberandy, wanting to restrict invalid syntax, values, or both?

le717 commented 9 years ago

Sorry about that, on mobile ATM. Hit the wrong button. :)

andythenorth commented 9 years ago

For my case, invalid syntax, specifically cases like "fff" and "rgb 255 0 0".

Invalid values are already caught by calling isValid() against user input (and showing failure appropriately to user). :)

le717 commented 9 years ago

Hmmm... I have an idea for this. Will post later.

le717 commented 9 years ago

I wish I could explain further, but I GTG and can't until tomorrow. :(

Anyway, my idea was to check the input against a regex / charAt(0) (for Hex) that searched for proper structure, then returned true or false on the outcome. The color format would be determined as best as possible before checking against the regex. Rough idea of what I refer to (download and run, sorry, no JSFiddle):

https://gist.github.com/le717/63faf91c76c99fb0952f

Thoughts?

le717 commented 9 years ago

@teamrubberandy @bgrins That was one long tomorrow. :stuck_out_tongue:

Here is my idea for the code behind isValidCSSColor(), which does not use the DOM.

  1. Start by checking the input type (rgb/hsv, hex, keyword)
  2. If keyword, check if it is a key in tinycolor.names and return that (tinycolor.names[color] !== undefined
  3. If hex, a simple value.charAt(0) === "#" should do.
  4. If rgb/hsv, use a regex (that still allows flexible input) to confirm the syntax.
  5. If it is in scope of the method purpose, run the last two though isValid().

My gist linked above is a proof-of-concept way of performing the hex and rgb/hsv validiation. The latter's regex would need expanding to support more whitespace in the value, but as you can see by running the code, it does accurately check the syntax validity.