Looking for something?

Overview

As many readers know, the built-in Prototype JS validation library can handle a plethora of validation cases.  What some readers don't know is that many of these test cases were built all the way back in 2007!  The web has changed a lot since then!  One validation function that sticks out like a sore thumb is validate-css-length.

The Built-In Validator

Dissection

Let's start by dissecting the built-in validate-css-length function. 

['validate-css-length', 'Please input a valid CSS-length. For example 100px or 77pt or 20em or .5ex or 50%.', function (v) {
    if (v != '' && v) {
        return /^[0-9\.]+(px|pt|em|ex|%)?$/.test(v) && (!(/\..*\./.test(v))) && !(/\.$/.test(v));
    }
    return true;
}]

Ok, so before we get our regex-fu exercise underway, the first thing that the validation function does is check to see if the input is not an empty string and that the input is a truthy value.  This causes an empty string to always be accepted as valid input.  If a non-empty string is provided, the regular expressions are evaluated.

/^[0-9\.]+(px|pt|em|ex|%)?$/.test(v)

This expression will match input in the following form:

  1. Match one of the following characters between 1 and an infinite number of times: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, .
  2. Optionally match one of the following character sequences: px, pt, em, ex, %
/\..*\./.test(v)

This expression will match input in the following form (note - the result of this match is negated by the preceding ! token):

  1. Match a single . character literally
  2. Match any character between 0 and an infinite number of times
  3. Match a single . character literally

The expression basically makes sure that sequences in the form of 1.2.3.4 fail to match.

/\.$/.test(v)

This expression will match input that consists of a single . character. (note - the result of this match is negated by the preceeding ! token)

So in a nutshell, the built-in validator will match any expression that is a valid integer and/or floating point number.  This number can have an optional px, pt, em, ex, or % symbol appended to it.

What's wrong with the built-in validator?

Negative lengths are not allowed

As the reader is probably well aware, negative CSS lengths are sometimes extremely useful!  The built-in validator has no accommodation for an optional - sign.

The auto, inherit, and initial keywords are not allowed

These three keywords are always allowed for a CSS length.  The auto keyword will automatically set the value based upon the content and/or the context of the element, the inherit keyword will take the value of the parent element, and the initial keyword will take the default value of the element.

Several length units are missing

Among the missing length units are: ch, rem, vh, vw, vmin, vmax, in, cm, mm, pc.

Modernizing The Validator

Rather than hacking up the default core validator (which has been known to cause cancer and/or birth defects in the state of California), a better solution would be to add a new validator to the global Validation object.  Depending on the situation of the reader, there are a couple of ways to go about this.

  1. Hack up the local.xml file.  If you aren't building a module that otherwise requires this validator, then this might be the best way to go.
  2. Create a module and add a custom layout file.  If you're building a third party module that requires this validator, then definitely add it to the new layout file.

After picking out the layout file(s) to modify, there is yet another fork in the road:

  1. Should I add this to all pages?
  2. Should I add this only to pages that need it?

For the sake of simplicity, this article will plop the layout update into the <default> node of the a newly created module.

<?xml version="1.0" encoding="utf-8"?>
<layout>
    <default>
        <reference name="head">
            <action method="addJs">
                <script>stabilis/validations.js</script>
            </action>
        </reference>
    </default>
</layout>

The above XML adds a javascript file to the head section of every page.  The javascript file contains the newly added validator.

if(Validation) {
    
    Validation.addAllThese([
        ['validate-modern-css-length', 
         'Please enter a valid CSS length', 
         function(value) {
             switch(value) {
                 case '':
                 case '0':
                 case 'auto':
                 case 'inherit':
                 case 'initial':
                     return true;
                 default:
                     return /^[+-]?(\d*\.)?\d+(%|ch|cm|ex|in|mm|px|pc|pt|r?em|vh|vmax|vmin|vw)$/.test(value);
             }
         }]
         ///...more validators to follow
    ]);
}

 The revamped validation method operates by first checking for "simple" conditions that do not require any regular expression processing.  These cases form an early, cheap, and easily understood exit from the function.  Don't take a rocket launcher to a knife fight if you don't have to, right?  If all else fails, then it's time to run a regular expression match to determine the validity of the input.

/^[+-]?(\d*\.)?\d+(%|ch|cm|ex|in|mm|px|pc|pt|r?em|vh|vmax|vmin|vw)$/.test(value);

This regular expression matches:

  1. An optional + or - sign
  2. An optional sequence that consists of any digit from 0 to infinite times followed by a . character
  3. One or more digits followed by one of %, ch, cm, ex, in, mm, px, pc, pt, em, rem, vh, vmax, vmin, or vw.

As most readers will have already inferred, to utilize the new validation method simply add the  validate-modern-css-length CSS class to any form input that is consumed by a Varien Form.

Conclusion

In this article, we have visited a part of the Magento validation library that was seemingly lost and forgotten over the course of time and breathed new life into it.  The validator code is bundled with the Stabilis Core extension that will be published on my github account when an alpha release is ready.