valibot 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +20 -0
 - data/README.md +250 -0
 - data/js/valibot.js +503 -0
 - data/lib/valibot.rb +117 -0
 - metadata +90 -0
 
    
        data/LICENSE
    ADDED
    
    | 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Copyright (c) 2011 Kenichi Nakamura
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Permission is hereby granted, free of charge, to any person obtaining
         
     | 
| 
      
 4 
     | 
    
         
            +
            a copy of this software and associated documentation files (the
         
     | 
| 
      
 5 
     | 
    
         
            +
            "Software"), to deal in the Software without restriction, including
         
     | 
| 
      
 6 
     | 
    
         
            +
            without limitation the rights to use, copy, modify, merge, publish,
         
     | 
| 
      
 7 
     | 
    
         
            +
            distribute, sublicense, and/or sell copies of the Software, and to
         
     | 
| 
      
 8 
     | 
    
         
            +
            permit persons to whom the Software is furnished to do so, subject to
         
     | 
| 
      
 9 
     | 
    
         
            +
            the following conditions:
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            The above copyright notice and this permission notice shall be
         
     | 
| 
      
 12 
     | 
    
         
            +
            included in all copies or substantial portions of the Software.
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
         
     | 
| 
      
 15 
     | 
    
         
            +
            EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
         
     | 
| 
      
 16 
     | 
    
         
            +
            MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
         
     | 
| 
      
 17 
     | 
    
         
            +
            NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
         
     | 
| 
      
 18 
     | 
    
         
            +
            LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
         
     | 
| 
      
 19 
     | 
    
         
            +
            OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
         
     | 
| 
      
 20 
     | 
    
         
            +
            WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         
     | 
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,250 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Valibot!
         
     | 
| 
      
 2 
     | 
    
         
            +
            ========
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            Automatic field validation for forms backed by DataMapper models through Sinatra.
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            What it requires:
         
     | 
| 
      
 7 
     | 
    
         
            +
            -----------------
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            * [Datamapper](http://datamapper.org/)
         
     | 
| 
      
 10 
     | 
    
         
            +
            * [Sinatra](http://sinatrarb.com/)
         
     | 
| 
      
 11 
     | 
    
         
            +
            * [Rack](http://rack.rubyforge.org/)
         
     | 
| 
      
 12 
     | 
    
         
            +
            * [jQuery](http://jquery.com/)
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            What it provides:
         
     | 
| 
      
 15 
     | 
    
         
            +
            -----------------
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            * full automatic field validation on default bind events
         
     | 
| 
      
 18 
     | 
    
         
            +
            * field value matching confirmation
         
     | 
| 
      
 19 
     | 
    
         
            +
            * extensible through callbacks used to build, place, remove, or transform error tags
         
     | 
| 
      
 20 
     | 
    
         
            +
            * Valibot#all method to do the whole thing at once.
         
     | 
| 
      
 21 
     | 
    
         
            +
            * automatic 'onsubmit' binding
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            To use (brief):
         
     | 
| 
      
 24 
     | 
    
         
            +
            -------
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            * add this gem to your Gemfile, bundle install
         
     | 
| 
      
 27 
     | 
    
         
            +
            * add the javascript to your site
         
     | 
| 
      
 28 
     | 
    
         
            +
            * add the app to your config.ru (defaults to '/_valibot')
         
     | 
| 
      
 29 
     | 
    
         
            +
            * create Valibots for the models on forms where you need them
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            To use (details):
         
     | 
| 
      
 32 
     | 
    
         
            +
            -----------------
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            ####to add the javascript to your site, there are two methods:
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            Valibot has a route at '/valibot.js' that will deliver the source. This is the *preferred* method:
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                <script src="/_valibot/valibot.js"></script>
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            Valibot *can* add a helper to Sinatra::Base called 'valibot_js'. call this in a script template like so:
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                <%= valibot_js %>
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            They deliver the exact same content, but the route adds Cache-Control headers so layers like Varnish or Rack::Cache can do their work. In order to use the helper, you need to register it in your app:
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                class App < Sinatra::Base
         
     | 
| 
      
 47 
     | 
    
         
            +
                  register Valibot::Helpers
         
     | 
| 
      
 48 
     | 
    
         
            +
                  get('/'){ erb "<script><%= valibot_js %></script>" }
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
            ####the sinatra app needs a place to run at in your Rack config. something like the following should suffice:
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                map '/_valibot' do
         
     | 
| 
      
 54 
     | 
    
         
            +
                  run Valibot::App
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
            note that you can change the path it runs at, but you must pass that path as a value to the Valibot javascript constructor using the key `pathPrefix` (see below).
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
            ####to create the Valibots, call the constructor inside $(document).ready():
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                $(document).ready(function(){ new Valibot({ modelName: 'user' }); });
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
            Constructor options:
         
     | 
| 
      
 64 
     | 
    
         
            +
            --------------------
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
            ####modelName : string *required if no `modelNames`*
         
     | 
| 
      
 67 
     | 
    
         
            +
            name of the model to validate against, in snake_case. in modern Rack-based webapps, the convention for form field names is to follow a `model_name[field_name]` pattern. Rack translates these names into the params hash and it is very common for the controller to pass this hash to a model constructor like `ModelName.new params['model_name']`.  your form should follow this convention for Valibot to work, as it will use jQuery to select all `input`, `textarea`, and `select` tags from the DOM that have names that start with this value. ex:
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                <input type="text" name="user[first_name]"/>
         
     | 
| 
      
 70 
     | 
    
         
            +
                <input type="text" name="user[email]"/>
         
     | 
| 
      
 71 
     | 
    
         
            +
                ...
         
     | 
| 
      
 72 
     | 
    
         
            +
                new Valibot({ modelName: 'user' });
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
            ---
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
            ####modelNames : array of strings *required if no `modelName`*
         
     | 
| 
      
 77 
     | 
    
         
            +
            names of the models to validate against, in snake_case. this behaves exactly like `modelName` but allows multiple models to be validated in the same form.  ex:
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                <input type="text" name="user[first_name]"/>
         
     | 
| 
      
 80 
     | 
    
         
            +
                <input type="text" name="profile[bio]"/>
         
     | 
| 
      
 81 
     | 
    
         
            +
                ...
         
     | 
| 
      
 82 
     | 
    
         
            +
                new Valibot({ modelNames: ['user', 'profile'] });
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
            note that the first invalid field of the _first model specified_ will be `focus()`ed if the form fails validation on submit.
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
            ---
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
            ####pathPrefix : string
         
     | 
| 
      
 89 
     | 
    
         
            +
            path you have Valibot racked up at. ex:
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                new Valibot({ modelName: 'user', pathPrefix: 'dogs_and_cats' });
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
            ---
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
            ####errorTagBuilder : function(text, self, minion)
         
     | 
| 
      
 96 
     | 
    
         
            +
            a callback for building the tag you want to put in the DOM and show the user with the error message from DataMapper in it. the default builder will create an `<em>` element, set its class to 'error', innerHTML `text` in, and return it.
         
     | 
| 
      
 97 
     | 
    
         
            +
            ######parameters:
         
     | 
| 
      
 98 
     | 
    
         
            +
            * `text` - error message from DataMapper
         
     | 
| 
      
 99 
     | 
    
         
            +
            * `self` - reference to the Valibot object
         
     | 
| 
      
 100 
     | 
    
         
            +
            * `minion` - reference to the Valitron or Confirm-o-mat object
         
     | 
| 
      
 101 
     | 
    
         
            +
            ######returns:
         
     | 
| 
      
 102 
     | 
    
         
            +
            * an element with the `text` in it suitable for placing in to the DOM.
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
            ---
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
            ####errorTagPlacer : function(tag, errorTag, self, minion)
         
     | 
| 
      
 107 
     | 
    
         
            +
            a callback for placing the element returned from the builder into the DOM.
         
     | 
| 
      
 108 
     | 
    
         
            +
            ######parameters:
         
     | 
| 
      
 109 
     | 
    
         
            +
            * `tag` - the field element whose value is being validated
         
     | 
| 
      
 110 
     | 
    
         
            +
            * `errorTag` - the element built and returned by the `errorTagBuilder` function of this Valibot
         
     | 
| 
      
 111 
     | 
    
         
            +
            * `self` - reference to the Valibot object
         
     | 
| 
      
 112 
     | 
    
         
            +
            * `minion` - reference to the Valitron or Confirm-o-mat object
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
            ---
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
            ####errorTagRemover : function(errorTag, self, minion)
         
     | 
| 
      
 117 
     | 
    
         
            +
            a callback for removing the element from the DOM in the event of no error found.
         
     | 
| 
      
 118 
     | 
    
         
            +
            ######parameters:
         
     | 
| 
      
 119 
     | 
    
         
            +
            * `errorTag` - the element in the DOM that holds the error message for this field
         
     | 
| 
      
 120 
     | 
    
         
            +
            * `self` - reference to the Valibot object
         
     | 
| 
      
 121 
     | 
    
         
            +
            * `minion` - reference to the Valitron or Confirm-o-mat object
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
            ---
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
            ####errorTagTransformer : function(text, errorTag, self, minion)
         
     | 
| 
      
 126 
     | 
    
         
            +
            a callback for transforming the element in the DOM in the event of a new error message replacing an old one.
         
     | 
| 
      
 127 
     | 
    
         
            +
            ######parameters:
         
     | 
| 
      
 128 
     | 
    
         
            +
            * `text` - error message from DataMapper
         
     | 
| 
      
 129 
     | 
    
         
            +
            * `errorTag` - the element in the DOM that holds the error message for this field
         
     | 
| 
      
 130 
     | 
    
         
            +
            * `self` - reference to the Valibot object
         
     | 
| 
      
 131 
     | 
    
         
            +
            * `minion` - reference to the Valitron or Confirm-o-mat object
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
            ---
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
            ####include : array or map { modelName : array }
         
     | 
| 
      
 136 
     | 
    
         
            +
            by default, Valibot will attach Valitrons to elements whose name attribute matches a specific regular expression, after jQuery selection. you can force fields whose name attributes don't match the regex to be checked by Valibot by putting the field name in this array. i'm not actually sure when this would be needed. :)
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
            ---
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
            ####exclude : array or map { modelName : array }
         
     | 
| 
      
 141 
     | 
    
         
            +
            you can keep Valibot from attaching Valitrons to certain elements by putting their field names in this
         
     | 
| 
      
 142 
     | 
    
         
            +
            array. ex:
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
                new Valibot({ modelName: 'user', exclude: ['middle_name'] });
         
     | 
| 
      
 145 
     | 
    
         
            +
                
         
     | 
| 
      
 146 
     | 
    
         
            +
                new Valibot({ modelNames: ['user', 'profile'], exclude: {'user': ['middle_name'], 'profile': ['icon']});
         
     | 
| 
      
 147 
     | 
    
         
            +
             
     | 
| 
      
 148 
     | 
    
         
            +
            ---
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
            ####bindEvents : map { fieldName : event }
         
     | 
| 
      
 151 
     | 
    
         
            +
            Valibot has a fairly intuitive default bind event for each input type: `change` for checkboxes, radio buttons, and select drop-downs; `blur` for everything else. you can override these defaults on a per-field basis by passing them in this hash. ex:
         
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
                new Valibot({ modelName: 'user', bindEvents: {'middle_name':'keyup'} });
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
            ---
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
            ####context : string
         
     | 
| 
      
 158 
     | 
    
         
            +
            DataMapper has contextual validations built-in. if you need to validate against a certain context, pass it in here.  ex:
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
                new Valibot({ modelName: 'user', context: 'signup' });
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
            ---
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
            ####confirm : array of maps { id : things }
         
     | 
| 
      
 165 
     | 
    
         
            +
            often on a form, one will have an 'extra' field that is not part of the data model, but needs to match another field in value. usually, these are passwords or email addresses. in this case, if you have given the actual model field element an id of 'password', the confirmation field id should be 'confirm_password'. then you can tell Valibot about this by passing this array of hashes and it will attach a Confirm-o-mat to each. `things` is the word that the Confirm-o-mat will use in its error message about the things not matching. ex:
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
                new Valibot({ modelName: 'user', confirm: [{'password', 'Passwords'}] });
         
     | 
| 
      
 168 
     | 
    
         
            +
             
     | 
| 
      
 169 
     | 
    
         
            +
            this would attach a Confirm-o-mat to `$('#confirm_password')` that checks its value against `$('#password').val()` and will build an errorTag with the text, "Passwords do not match."
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
            ---
         
     | 
| 
      
 172 
     | 
    
         
            +
             
     | 
| 
      
 173 
     | 
    
         
            +
            ####agreements : array of maps { id : things }
         
     | 
| 
      
 174 
     | 
    
         
            +
            often on a form, one will have a checkbox that is not part of the data model, but needs to checked as a legally binding agreement. usually, these are rules or term and conditions, etc. in this case, simply give the input a unique id. then you can tell Valibot about it by passing this array of hashes and it will attach an Agree-Pee-Oh to each. `things` is the word that the Agree-Pee-Oh will use in its error message about the things not being agreed to. ex:
         
     | 
| 
      
 175 
     | 
    
         
            +
             
     | 
| 
      
 176 
     | 
    
         
            +
                new Valibot({ modelName: 'user', agreements: [{'rules', 'Rules'}] });
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
            this would attach an Agree-Pee-Oh to `$('#rules')` that verified it's checked and will build an errorTag with the text, "You must agree to the Rules." if it is not.
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
            ---
         
     | 
| 
      
 181 
     | 
    
         
            +
             
     | 
| 
      
 182 
     | 
    
         
            +
            ####fancy : boolean
         
     | 
| 
      
 183 
     | 
    
         
            +
            Valibot has two built-in types of errorTag(Placer|Remover|Transformer) functions. the default is very bland and simply inserts, replaces, or removes the errorTag element. the fancy option uses jQuery animation to fadeIn and fadeOut the errorTag element. if this is `true`, and you also feed it your own errorTag callbacks, those will be used instead. ex:
         
     | 
| 
      
 184 
     | 
    
         
            +
             
     | 
| 
      
 185 
     | 
    
         
            +
                new Valibot({ modelName: 'user', fancy: true, errorTagPlacer: myETPlacer });
         
     | 
| 
      
 186 
     | 
    
         
            +
             
     | 
| 
      
 187 
     | 
    
         
            +
            this would utilize the "fancy" Remover and Transformer built-in functions, but call `myETPlacer()` for placement.  note that the `_fancyErrorTagTransformer` function actually calls whatever Placer function is set in the containing Valibot; in this case, `myETPlacer`.
         
     | 
| 
      
 188 
     | 
    
         
            +
             
     | 
| 
      
 189 
     | 
    
         
            +
            ---
         
     | 
| 
      
 190 
     | 
    
         
            +
             
     | 
| 
      
 191 
     | 
    
         
            +
            ####bindOnSubmit : boolean
         
     | 
| 
      
 192 
     | 
    
         
            +
            Valibot automatically binds it's own `onSubmit()` function to the first form that it finds model fields in. this function will run through any unchecked or invalid 'trons or 'mats and call their `checkValue()` functions. once that is complete, if all of them are valid, it submits the form; otherwise, error messages are built/placed like normal, and the first invalid field is focus()ed. this flag allows you to turn off this functionality, for cases where you need to do your own onsubmit dance. note that the Valibot's onsubmit can be called in this situation anyway; but, be careful because it will submit the form if everything is valid. ex:
         
     | 
| 
      
 193 
     | 
    
         
            +
             
     | 
| 
      
 194 
     | 
    
         
            +
                var valibot = new Valibot({ modelName: 'user', bindOnSubmit: false });
         
     | 
| 
      
 195 
     | 
    
         
            +
                $(valibot.form).bind('submit', function(event) {
         
     | 
| 
      
 196 
     | 
    
         
            +
                  event.preventDefault();
         
     | 
| 
      
 197 
     | 
    
         
            +
             
     | 
| 
      
 198 
     | 
    
         
            +
                  // do something clever
         
     | 
| 
      
 199 
     | 
    
         
            +
             
     | 
| 
      
 200 
     | 
    
         
            +
                  valibot.onSubmit();
         
     | 
| 
      
 201 
     | 
    
         
            +
                });
         
     | 
| 
      
 202 
     | 
    
         
            +
             
     | 
| 
      
 203 
     | 
    
         
            +
            ---
         
     | 
| 
      
 204 
     | 
    
         
            +
             
     | 
| 
      
 205 
     | 
    
         
            +
            ####submitForm : boolean
         
     | 
| 
      
 206 
     | 
    
         
            +
            sometimes, you just want to submit the form yourself.  most of the time, you want to do it all AJAX fancypants.  fine, just pass this in as `false` and Valibot won't try to submit the form.  it will still call `onSubmitCallback` so you probably want to put your XHRs in there.
         
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
      
 208 
     | 
    
         
            +
            ---
         
     | 
| 
      
 209 
     | 
    
         
            +
             
     | 
| 
      
 210 
     | 
    
         
            +
            ####onSubmitCallback : function(valibot)
         
     | 
| 
      
 211 
     | 
    
         
            +
            set this to a function you want to run when the form would be submitted.  if you set `submitForm` to false, this function will be called, but the form WILL NOT be submitted.  use these two together to get Valibot validation on forms you want to submit XHR-style. ex:
         
     | 
| 
      
 212 
     | 
    
         
            +
             
     | 
| 
      
 213 
     | 
    
         
            +
                var valibot = new Valibot({ modelName: 'foo', submitForm: false, onSubmitCallback: function(valibot) {
         
     | 
| 
      
 214 
     | 
    
         
            +
                  $.post(valibot.form.action, $(valibot.form).serialize(), function(response){ /* ... /* });
         
     | 
| 
      
 215 
     | 
    
         
            +
                }});
         
     | 
| 
      
 216 
     | 
    
         
            +
             
     | 
| 
      
 217 
     | 
    
         
            +
            ---
         
     | 
| 
      
 218 
     | 
    
         
            +
             
     | 
| 
      
 219 
     | 
    
         
            +
            ####appUrl : string
         
     | 
| 
      
 220 
     | 
    
         
            +
            perhaps you want to run Valibot at a different URL completely from the one that the form your validating loaded from.  fine, just tell Valibot about it with this.  note that this puts Valibot into JSONP mode and all validation requests turn from POSTs into GETs. ex:
         
     | 
| 
      
 221 
     | 
    
         
            +
             
     | 
| 
      
 222 
     | 
    
         
            +
                new Valibot({ modelName: 'user', appUrl: 'http://some.other.domain/'});
         
     | 
| 
      
 223 
     | 
    
         
            +
             
     | 
| 
      
 224 
     | 
    
         
            +
            this would cause all validation requests to go to 'http://some.other.domain/_valibot/:model/...'
         
     | 
| 
      
 225 
     | 
    
         
            +
             
     | 
| 
      
 226 
     | 
    
         
            +
            ---
         
     | 
| 
      
 227 
     | 
    
         
            +
             
     | 
| 
      
 228 
     | 
    
         
            +
            ####dependents : map of arrays { field : [ otherField, ... ] }
         
     | 
| 
      
 229 
     | 
    
         
            +
            sometimes you need to validate a field based off of the value of another field.  you can tell Valibot about this with this option, and it will automatically include the value(s) of the other field(s) in the validation. ex:
         
     | 
| 
      
 230 
     | 
    
         
            +
             
     | 
| 
      
 231 
     | 
    
         
            +
                new Valibot({ modelName: 'user', dependents: {'last_name': ['first_name']} });
         
     | 
| 
      
 232 
     | 
    
         
            +
             
     | 
| 
      
 233 
     | 
    
         
            +
            this would cause Valibot to POST the value of the field named 'user[first_name]' with the check request for 'last_name'. your model should be configured to validate `last_name` based off of the value of `first_name`:
         
     | 
| 
      
 234 
     | 
    
         
            +
             
     | 
| 
      
 235 
     | 
    
         
            +
                validates_with_block :last_name do
         
     | 
| 
      
 236 
     | 
    
         
            +
                  if self.first_name == 'a' and self.last_name == 'b'
         
     | 
| 
      
 237 
     | 
    
         
            +
                    [false, "can't have b with a."]
         
     | 
| 
      
 238 
     | 
    
         
            +
                  else
         
     | 
| 
      
 239 
     | 
    
         
            +
                    true
         
     | 
| 
      
 240 
     | 
    
         
            +
                  end
         
     | 
| 
      
 241 
     | 
    
         
            +
                end
         
     | 
| 
      
 242 
     | 
    
         
            +
             
     | 
| 
      
 243 
     | 
    
         
            +
            note that in the above example, `first_name` would still be validated on it's own.
         
     | 
| 
      
 244 
     | 
    
         
            +
             
     | 
| 
      
 245 
     | 
    
         
            +
            Next Steps (TODOS):
         
     | 
| 
      
 246 
     | 
    
         
            +
            -------------------
         
     | 
| 
      
 247 
     | 
    
         
            +
             
     | 
| 
      
 248 
     | 
    
         
            +
            * automated testing (!!)
         
     | 
| 
      
 249 
     | 
    
         
            +
            * array parameters
         
     | 
| 
      
 250 
     | 
    
         
            +
            * profit!
         
     | 
    
        data/js/valibot.js
    ADDED
    
    | 
         @@ -0,0 +1,503 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            /* valibot.js (c) 2011 kenichi nakamura (kenichi.nakamura@gmail.com)
         
     | 
| 
      
 2 
     | 
    
         
            +
             *
         
     | 
| 
      
 3 
     | 
    
         
            +
             * javascript class for easy automatic form field validation against datamapper
         
     | 
| 
      
 4 
     | 
    
         
            +
             * models behind a sinatra app.
         
     | 
| 
      
 5 
     | 
    
         
            +
             *
         
     | 
| 
      
 6 
     | 
    
         
            +
             * see ____ for details.  TODO
         
     | 
| 
      
 7 
     | 
    
         
            +
             */
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            //  regex to make sure we only grab fields whose 'name' attrs match
         
     | 
| 
      
 10 
     | 
    
         
            +
            var _valibotFieldRegExp = new RegExp('^\\w+\\[[^\\]]+\\]$');
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            if (Array.prototype.indexOf == null) {
         
     | 
| 
      
 13 
     | 
    
         
            +
              Array.prototype.indexOf = function(obj) {
         
     | 
| 
      
 14 
     | 
    
         
            +
                for (var i = 0; i < this.length; i++) {
         
     | 
| 
      
 15 
     | 
    
         
            +
                  if (this[i] == obj) {
         
     | 
| 
      
 16 
     | 
    
         
            +
                    return i;
         
     | 
| 
      
 17 
     | 
    
         
            +
                  }
         
     | 
| 
      
 18 
     | 
    
         
            +
                }
         
     | 
| 
      
 19 
     | 
    
         
            +
                return -1;
         
     | 
| 
      
 20 
     | 
    
         
            +
              };
         
     | 
| 
      
 21 
     | 
    
         
            +
            }
         
     | 
| 
      
 22 
     | 
    
         
            +
            Array.prototype.contains = function(obj){ return this.indexOf(obj) != -1; };
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            /* the Valibot class. create an object of this class and feed it a model name. oh,
         
     | 
| 
      
 25 
     | 
    
         
            +
             * and options too if you want. the object, during construction, will attach
         
     | 
| 
      
 26 
     | 
    
         
            +
             * Valitrons (see below) to each field it finds that matches the modelName specified.
         
     | 
| 
      
 27 
     | 
    
         
            +
             * it will also attach Confirmomats (see below) to any field specified as a
         
     | 
| 
      
 28 
     | 
    
         
            +
             * confirmation field.
         
     | 
| 
      
 29 
     | 
    
         
            +
             */
         
     | 
| 
      
 30 
     | 
    
         
            +
            function Valibot(opts) {
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
              this.pathPrefix =          '_valibot';
         
     | 
| 
      
 33 
     | 
    
         
            +
              this.modelNames =          [];
         
     | 
| 
      
 34 
     | 
    
         
            +
              this.errorTagPlacer =      this._defaultErrorTagPlacer;
         
     | 
| 
      
 35 
     | 
    
         
            +
              this.errorTagBuilder =     this._defaultErrorTagBuilder;
         
     | 
| 
      
 36 
     | 
    
         
            +
              this.errorTagRemover =     this._defaultErrorTagRemover;
         
     | 
| 
      
 37 
     | 
    
         
            +
              this.errorTagTransformer = this._defaultErrorTagTransformer;
         
     | 
| 
      
 38 
     | 
    
         
            +
              this.include =             {};
         
     | 
| 
      
 39 
     | 
    
         
            +
              this.exclude =             {};
         
     | 
| 
      
 40 
     | 
    
         
            +
              this.bindEvents =          {};
         
     | 
| 
      
 41 
     | 
    
         
            +
              this.context =             null;
         
     | 
| 
      
 42 
     | 
    
         
            +
              this.confirm =             [];
         
     | 
| 
      
 43 
     | 
    
         
            +
              this.confirmomats =        [];
         
     | 
| 
      
 44 
     | 
    
         
            +
              this.valitrons =           [];
         
     | 
| 
      
 45 
     | 
    
         
            +
              this.valids =              [];
         
     | 
| 
      
 46 
     | 
    
         
            +
              this.invalids =            [];
         
     | 
| 
      
 47 
     | 
    
         
            +
              this.bindOnSubmit =        true;
         
     | 
| 
      
 48 
     | 
    
         
            +
              this.submitForm =          true;
         
     | 
| 
      
 49 
     | 
    
         
            +
              this.onSubmitCallback =    null;
         
     | 
| 
      
 50 
     | 
    
         
            +
              this.agreements =          [];
         
     | 
| 
      
 51 
     | 
    
         
            +
              this.agreepeeohs =         [];
         
     | 
| 
      
 52 
     | 
    
         
            +
              this.formId =              '';
         
     | 
| 
      
 53 
     | 
    
         
            +
              this.appUrl =              null;
         
     | 
| 
      
 54 
     | 
    
         
            +
              this.dependents =          {};
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
              if (opts != null) {
         
     | 
| 
      
 57 
     | 
    
         
            +
                if (opts.fancy != null && opts.fancy) {
         
     | 
| 
      
 58 
     | 
    
         
            +
                  this.errorTagPlacer =      this._fancyErrorTagPlacer;
         
     | 
| 
      
 59 
     | 
    
         
            +
                  this.errorTagRemover =     this._fancyErrorTagRemover;
         
     | 
| 
      
 60 
     | 
    
         
            +
                  this.errorTagTransformer = this._fancyErrorTagTransformer;
         
     | 
| 
      
 61 
     | 
    
         
            +
                }
         
     | 
| 
      
 62 
     | 
    
         
            +
                if (opts.modelName != null)             this.modelNames =          [opts.modelName];
         
     | 
| 
      
 63 
     | 
    
         
            +
                if (opts.modelNames != null)            this.modelNames =          opts.modelNames;
         
     | 
| 
      
 64 
     | 
    
         
            +
                if (opts.pathPrefix != null)            this.pathPrefix =          opts.pathPrefix;
         
     | 
| 
      
 65 
     | 
    
         
            +
                if (opts.errorTagPlacer != null)        this.errorTagPlacer =      opts.errorTagPlacer;
         
     | 
| 
      
 66 
     | 
    
         
            +
                if (opts.errorTagBuilder != null)       this.errorTagBuilder =     opts.errorTagBuilder;
         
     | 
| 
      
 67 
     | 
    
         
            +
                if (opts.errorTagRemover != null)       this.errorTagRemover =     opts.errorTagRemover;
         
     | 
| 
      
 68 
     | 
    
         
            +
                if (opts.errorTagTransformer != null)   this.errorTagTransformer = opts.errorTagTransformer;
         
     | 
| 
      
 69 
     | 
    
         
            +
                if (opts.bindEvents != null)            this.bindEvents =          opts.bindEvents;
         
     | 
| 
      
 70 
     | 
    
         
            +
                if (opts.context != null)               this.context =             opts.context;
         
     | 
| 
      
 71 
     | 
    
         
            +
                if (opts.confirm != null)               this.confirm =             opts.confirm;
         
     | 
| 
      
 72 
     | 
    
         
            +
                if (opts.bindOnSubmit != null)          this.bindOnSubmit =        opts.bindOnSubmit;
         
     | 
| 
      
 73 
     | 
    
         
            +
                if (opts.submitForm != null)            this.submitForm =          opts.submitForm;
         
     | 
| 
      
 74 
     | 
    
         
            +
                if (opts.onSubmitCallback != null)      this.onSubmitCallback =    opts.onSubmitCallback;
         
     | 
| 
      
 75 
     | 
    
         
            +
                if (opts.agreements != null)            this.agreements =          opts.agreements;
         
     | 
| 
      
 76 
     | 
    
         
            +
                if (opts.formId != null)                this.formId =              '#' + opts.formId + ' ';
         
     | 
| 
      
 77 
     | 
    
         
            +
                if (opts.appUrl != null)                this.appUrl =              opts.appUrl;
         
     | 
| 
      
 78 
     | 
    
         
            +
                if (opts.dependents != null)            this.dependents =          opts.dependents;
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                if (opts.include != null) {
         
     | 
| 
      
 81 
     | 
    
         
            +
                  if (opts.include instanceof Array) {
         
     | 
| 
      
 82 
     | 
    
         
            +
                    this.include[this.modelNames[0]] = opts.include;
         
     | 
| 
      
 83 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 84 
     | 
    
         
            +
                    this.include = opts.include;
         
     | 
| 
      
 85 
     | 
    
         
            +
                  }
         
     | 
| 
      
 86 
     | 
    
         
            +
                }
         
     | 
| 
      
 87 
     | 
    
         
            +
                if (opts.exclude != null) {
         
     | 
| 
      
 88 
     | 
    
         
            +
                  if (opts.exclude instanceof Array) {
         
     | 
| 
      
 89 
     | 
    
         
            +
                    this.exclude[this.modelNames[0]] = opts.exclude;
         
     | 
| 
      
 90 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 91 
     | 
    
         
            +
                    this.exclude = opts.exclude;
         
     | 
| 
      
 92 
     | 
    
         
            +
                  }
         
     | 
| 
      
 93 
     | 
    
         
            +
                }
         
     | 
| 
      
 94 
     | 
    
         
            +
                 
         
     | 
| 
      
 95 
     | 
    
         
            +
              }
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
              var _this = this;
         
     | 
| 
      
 98 
     | 
    
         
            +
              $(this.modelNames).each(function(i, modelName) {
         
     | 
| 
      
 99 
     | 
    
         
            +
                $(_this.formId + 'input[name^=' +    modelName + '], ' +
         
     | 
| 
      
 100 
     | 
    
         
            +
                  _this.formId + 'select[name^=' +   modelName + '], ' +
         
     | 
| 
      
 101 
     | 
    
         
            +
                  _this.formId + 'textarea[name^=' + modelName + ']').each(function(i,f) {
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                  var _name = $(f).attr('name');
         
     | 
| 
      
 104 
     | 
    
         
            +
                  var field = _name.substring(_name.indexOf('[') + 1, _name.length - 1);
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                  var _type = f.type.toLowerCase();
         
     | 
| 
      
 107 
     | 
    
         
            +
                  var _defaultBindEvent = 'blur';
         
     | 
| 
      
 108 
     | 
    
         
            +
                  if (_type == 'checkbox' || _type == 'radio' || _type == 'select-one' || _type == 'select-multiple')
         
     | 
| 
      
 109 
     | 
    
         
            +
                    _defaultBindEvent = 'change';
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                  var bindEvent = (_this.bindEvents[field] != null) ? _this.bindEvents[field] : _defaultBindEvent;
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                  if (_this.include[modelName] instanceof Array && _this.include[modelName].indexOf(field) != -1) {
         
     | 
| 
      
 114 
     | 
    
         
            +
                    _this.valitrons.push(new Valitron(f, modelName, field, bindEvent, _this));
         
     | 
| 
      
 115 
     | 
    
         
            +
                  } else if (_this.exclude[modelName] instanceof Array && _this.exclude[modelName].indexOf(field) != -1) {
         
     | 
| 
      
 116 
     | 
    
         
            +
                    // NOOP
         
     | 
| 
      
 117 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 118 
     | 
    
         
            +
                    if (_valibotFieldRegExp.test(f.name))
         
     | 
| 
      
 119 
     | 
    
         
            +
                      _this.valitrons.push(new Valitron(f, modelName, field, bindEvent, _this));
         
     | 
| 
      
 120 
     | 
    
         
            +
                  }
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
                });
         
     | 
| 
      
 123 
     | 
    
         
            +
              });
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
              if (this.confirm != null && this.confirm.length > 0) {
         
     | 
| 
      
 126 
     | 
    
         
            +
                $(this.confirm).each(function(i,c) {
         
     | 
| 
      
 127 
     | 
    
         
            +
                  $.each(c, function(id, things) { _this.confirmomats.push(new Confirmomat(id, things, _this)); });
         
     | 
| 
      
 128 
     | 
    
         
            +
                });
         
     | 
| 
      
 129 
     | 
    
         
            +
              }
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
              if (this.agreements != null && this.agreements.length > 0) {
         
     | 
| 
      
 132 
     | 
    
         
            +
                $(this.agreements).each(function(i,c) {
         
     | 
| 
      
 133 
     | 
    
         
            +
                  $.each(c, function(id, things) { _this.agreepeeohs.push(new AgreePeeOh(id, things, _this)); });
         
     | 
| 
      
 134 
     | 
    
         
            +
                });
         
     | 
| 
      
 135 
     | 
    
         
            +
              }
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
              this.form = this.valitrons.concat(this.confirmomats).concat(this.agreepeeohs)[0].tag.form;
         
     | 
| 
      
 138 
     | 
    
         
            +
              if (this.bindOnSubmit)
         
     | 
| 
      
 139 
     | 
    
         
            +
                $(this.form).submit(function(e){ e.preventDefault(); _this.onSubmit(); });
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
            }
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
            Valibot.prototype = {
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
              addValid:
         
     | 
| 
      
 146 
     | 
    
         
            +
                function(good) {
         
     | 
| 
      
 147 
     | 
    
         
            +
                  if (!this.valids.contains(good))  this.valids.push(good);
         
     | 
| 
      
 148 
     | 
    
         
            +
                  if (this.invalids.contains(good)) this.invalids.splice(this.invalids.indexOf(good), 1);
         
     | 
| 
      
 149 
     | 
    
         
            +
                },
         
     | 
| 
      
 150 
     | 
    
         
            +
             
     | 
| 
      
 151 
     | 
    
         
            +
              removeValid:
         
     | 
| 
      
 152 
     | 
    
         
            +
                function(remove) {
         
     | 
| 
      
 153 
     | 
    
         
            +
                  if (this.valids.contains(remove)) this.valids.splice(this.valids.indexOf(remove), 1);
         
     | 
| 
      
 154 
     | 
    
         
            +
                },
         
     | 
| 
      
 155 
     | 
    
         
            +
             
     | 
| 
      
 156 
     | 
    
         
            +
              addInvalid:
         
     | 
| 
      
 157 
     | 
    
         
            +
                function(bad) {
         
     | 
| 
      
 158 
     | 
    
         
            +
                  if (!this.invalids.contains(bad)) this.invalids.push(bad);
         
     | 
| 
      
 159 
     | 
    
         
            +
                  this.removeValid(bad);
         
     | 
| 
      
 160 
     | 
    
         
            +
                },
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
              unchecked:
         
     | 
| 
      
 163 
     | 
    
         
            +
                function() {
         
     | 
| 
      
 164 
     | 
    
         
            +
                  var uc = [];
         
     | 
| 
      
 165 
     | 
    
         
            +
                  var _this = this;
         
     | 
| 
      
 166 
     | 
    
         
            +
                  $(this.valitrons).each(function(i,tron){ if (!_this.valids.contains(tron) && !_this.invalids.contains(tron)) uc.push(tron); });
         
     | 
| 
      
 167 
     | 
    
         
            +
                  $(this.confirmomats).each(function(i,mat){ if (!_this.valids.contains(mat) && !_this.invalids.contains(mat)) uc.push(mat); });
         
     | 
| 
      
 168 
     | 
    
         
            +
                  $(this.agreepeeohs).each(function(i,oh){ if (!_this.valids.contains(oh) && !_this.invalids.contains(oh)) uc.push(oh); });
         
     | 
| 
      
 169 
     | 
    
         
            +
                  return uc;
         
     | 
| 
      
 170 
     | 
    
         
            +
                },
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
              allValid:
         
     | 
| 
      
 173 
     | 
    
         
            +
                function() {
         
     | 
| 
      
 174 
     | 
    
         
            +
                  return this.invalids.length == 0 &&
         
     | 
| 
      
 175 
     | 
    
         
            +
                    this.valids.length == this.valitrons.length + this.confirmomats.length + this.agreepeeohs.length;
         
     | 
| 
      
 176 
     | 
    
         
            +
                },
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
              onSubmit:
         
     | 
| 
      
 179 
     | 
    
         
            +
                function() {
         
     | 
| 
      
 180 
     | 
    
         
            +
                  if (!this.allValid()) {
         
     | 
| 
      
 181 
     | 
    
         
            +
                    this.checking = this.invalids.concat(this.unchecked());
         
     | 
| 
      
 182 
     | 
    
         
            +
                    var _this = this;
         
     | 
| 
      
 183 
     | 
    
         
            +
                    $(this.invalids).each(function(i, bad){ bad.checkValue(null, function(valid) { _this.onSubmitCheckCallback(bad); }); });
         
     | 
| 
      
 184 
     | 
    
         
            +
                    $(this.unchecked()).each(function(i, uc){ uc.checkValue(null, function(valid) { _this.onSubmitCheckCallback(uc); }); });
         
     | 
| 
      
 185 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 186 
     | 
    
         
            +
                    if (this.submitForm) {
         
     | 
| 
      
 187 
     | 
    
         
            +
                      this.form.submit();
         
     | 
| 
      
 188 
     | 
    
         
            +
                    } else if (typeof this.onSubmitCallback === 'function') {
         
     | 
| 
      
 189 
     | 
    
         
            +
                      this.onSubmitCallback(this);
         
     | 
| 
      
 190 
     | 
    
         
            +
                    }
         
     | 
| 
      
 191 
     | 
    
         
            +
                  }
         
     | 
| 
      
 192 
     | 
    
         
            +
                },
         
     | 
| 
      
 193 
     | 
    
         
            +
             
     | 
| 
      
 194 
     | 
    
         
            +
              onSubmitCheckCallback:
         
     | 
| 
      
 195 
     | 
    
         
            +
                function(tronOrMat, valid) {
         
     | 
| 
      
 196 
     | 
    
         
            +
                  this.checking.splice(this.checking.indexOf(tronOrMat), 1);
         
     | 
| 
      
 197 
     | 
    
         
            +
                  if (this.checking.length == 0) {
         
     | 
| 
      
 198 
     | 
    
         
            +
                    if (!this.allValid()) {
         
     | 
| 
      
 199 
     | 
    
         
            +
                      this.invalids[0].tag.focus();
         
     | 
| 
      
 200 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 201 
     | 
    
         
            +
                      if (this.submitForm) {
         
     | 
| 
      
 202 
     | 
    
         
            +
                        this.form.submit();
         
     | 
| 
      
 203 
     | 
    
         
            +
                      } else if (typeof this.onSubmitCallback === 'function') {
         
     | 
| 
      
 204 
     | 
    
         
            +
                        this.onSubmitCallback(this);
         
     | 
| 
      
 205 
     | 
    
         
            +
                      }
         
     | 
| 
      
 206 
     | 
    
         
            +
                    }
         
     | 
| 
      
 207 
     | 
    
         
            +
                  }
         
     | 
| 
      
 208 
     | 
    
         
            +
                },
         
     | 
| 
      
 209 
     | 
    
         
            +
             
     | 
| 
      
 210 
     | 
    
         
            +
              // never called by Valibot or its minions, but left here for utility.
         
     | 
| 
      
 211 
     | 
    
         
            +
              all:
         
     | 
| 
      
 212 
     | 
    
         
            +
                function(callback) {
         
     | 
| 
      
 213 
     | 
    
         
            +
                  var params = {};
         
     | 
| 
      
 214 
     | 
    
         
            +
                  $(this.valitrons).each(function(i, tron){ params[tron.tag.name] = tron.tag.value; });
         
     | 
| 
      
 215 
     | 
    
         
            +
                  var path = (this.appUrl != null ? this.appUrl : '') +
         
     | 
| 
      
 216 
     | 
    
         
            +
                             '/' + this.pathPrefix +
         
     | 
| 
      
 217 
     | 
    
         
            +
                             '/' + this.modelName +
         
     | 
| 
      
 218 
     | 
    
         
            +
                             (this.context != null ? ('/in/' + this.context) : '');
         
     | 
| 
      
 219 
     | 
    
         
            +
                  if (this.context != null)
         
     | 
| 
      
 220 
     | 
    
         
            +
                    path = path + '/in/' + this.context;
         
     | 
| 
      
 221 
     | 
    
         
            +
                  $.post(path, params, function(res){ callback(res) },
         
     | 
| 
      
 222 
     | 
    
         
            +
                         this.valibot.appUrl != null ? 'jsonp' : 'json');
         
     | 
| 
      
 223 
     | 
    
         
            +
                },
         
     | 
| 
      
 224 
     | 
    
         
            +
             
     | 
| 
      
 225 
     | 
    
         
            +
              _defaultErrorTagPlacer:
         
     | 
| 
      
 226 
     | 
    
         
            +
                function(tag, errorTag, self, minion) {
         
     | 
| 
      
 227 
     | 
    
         
            +
                  $(errorTag).insertAfter($(tag));
         
     | 
| 
      
 228 
     | 
    
         
            +
                },
         
     | 
| 
      
 229 
     | 
    
         
            +
             
     | 
| 
      
 230 
     | 
    
         
            +
              _defaultErrorTagBuilder:
         
     | 
| 
      
 231 
     | 
    
         
            +
                function(text, self, minion) {
         
     | 
| 
      
 232 
     | 
    
         
            +
                  var em = document.createElement('em');
         
     | 
| 
      
 233 
     | 
    
         
            +
                  em.className = 'error';
         
     | 
| 
      
 234 
     | 
    
         
            +
                  em.innerHTML = text;
         
     | 
| 
      
 235 
     | 
    
         
            +
                  return em;
         
     | 
| 
      
 236 
     | 
    
         
            +
                },
         
     | 
| 
      
 237 
     | 
    
         
            +
             
     | 
| 
      
 238 
     | 
    
         
            +
              _defaultErrorTagRemover:
         
     | 
| 
      
 239 
     | 
    
         
            +
                function(errorTag, self, callback, minion) {
         
     | 
| 
      
 240 
     | 
    
         
            +
                  var ret = $(errorTag).remove();
         
     | 
| 
      
 241 
     | 
    
         
            +
                  if (callback != null) callback(ret);
         
     | 
| 
      
 242 
     | 
    
         
            +
                },
         
     | 
| 
      
 243 
     | 
    
         
            +
             
     | 
| 
      
 244 
     | 
    
         
            +
              _defaultErrorTagTransformer:
         
     | 
| 
      
 245 
     | 
    
         
            +
                function(text, errorTag, self, minion) {
         
     | 
| 
      
 246 
     | 
    
         
            +
                  var em = this.errorTagBuilder(text, self, minion);
         
     | 
| 
      
 247 
     | 
    
         
            +
                  $(errorTag).replaceWith(em);
         
     | 
| 
      
 248 
     | 
    
         
            +
                  return em;
         
     | 
| 
      
 249 
     | 
    
         
            +
                },
         
     | 
| 
      
 250 
     | 
    
         
            +
             
     | 
| 
      
 251 
     | 
    
         
            +
              _fancyErrorTagPlacer:
         
     | 
| 
      
 252 
     | 
    
         
            +
                function(tag, errorTag, self, minion) {
         
     | 
| 
      
 253 
     | 
    
         
            +
                  $(errorTag).css('display', 'none');
         
     | 
| 
      
 254 
     | 
    
         
            +
                  $(errorTag).insertAfter($(tag));
         
     | 
| 
      
 255 
     | 
    
         
            +
                  $(errorTag).fadeIn();
         
     | 
| 
      
 256 
     | 
    
         
            +
                },
         
     | 
| 
      
 257 
     | 
    
         
            +
             
     | 
| 
      
 258 
     | 
    
         
            +
              _fancyErrorTagRemover:
         
     | 
| 
      
 259 
     | 
    
         
            +
                function(errorTag, self, minion) {
         
     | 
| 
      
 260 
     | 
    
         
            +
                  $(errorTag).fadeOut(null, null, function(){ $(errorTag).remove(); });
         
     | 
| 
      
 261 
     | 
    
         
            +
                },
         
     | 
| 
      
 262 
     | 
    
         
            +
             
     | 
| 
      
 263 
     | 
    
         
            +
              _fancyErrorTagTransformer:
         
     | 
| 
      
 264 
     | 
    
         
            +
                function(text, errorTag, self, minion) {
         
     | 
| 
      
 265 
     | 
    
         
            +
                  if (text == errorTag.innerHTML) {
         
     | 
| 
      
 266 
     | 
    
         
            +
                    return errorTag;
         
     | 
| 
      
 267 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 268 
     | 
    
         
            +
                    var newErrorTag = self.errorTagBuilder(text, self, minion);
         
     | 
| 
      
 269 
     | 
    
         
            +
                    $(errorTag).fadeOut(null, null, function() {
         
     | 
| 
      
 270 
     | 
    
         
            +
                      var tag = $(errorTag).prev();
         
     | 
| 
      
 271 
     | 
    
         
            +
                      $(errorTag).remove();
         
     | 
| 
      
 272 
     | 
    
         
            +
                      self.errorTagPlacer(tag, newErrorTag);
         
     | 
| 
      
 273 
     | 
    
         
            +
                    });
         
     | 
| 
      
 274 
     | 
    
         
            +
                    return newErrorTag;
         
     | 
| 
      
 275 
     | 
    
         
            +
                  }
         
     | 
| 
      
 276 
     | 
    
         
            +
                }
         
     | 
| 
      
 277 
     | 
    
         
            +
             
     | 
| 
      
 278 
     | 
    
         
            +
            };
         
     | 
| 
      
 279 
     | 
    
         
            +
             
     | 
| 
      
 280 
     | 
    
         
            +
            // ---
         
     | 
| 
      
 281 
     | 
    
         
            +
             
     | 
| 
      
 282 
     | 
    
         
            +
            /* the Valitron class. instantiated on each model form field by an overseeing
         
     | 
| 
      
 283 
     | 
    
         
            +
             * Valibot. handles the actual XHR between the JS and the valibot sinatra app.
         
     | 
| 
      
 284 
     | 
    
         
            +
             */
         
     | 
| 
      
 285 
     | 
    
         
            +
            function Valitron(tag, model, field, bindEvent, valibot) {
         
     | 
| 
      
 286 
     | 
    
         
            +
              this.valid = false;
         
     | 
| 
      
 287 
     | 
    
         
            +
              this.tag = tag;
         
     | 
| 
      
 288 
     | 
    
         
            +
              this.model = model;
         
     | 
| 
      
 289 
     | 
    
         
            +
              this.field = field;
         
     | 
| 
      
 290 
     | 
    
         
            +
              this.valibot = valibot;
         
     | 
| 
      
 291 
     | 
    
         
            +
              this.errorTag = null;
         
     | 
| 
      
 292 
     | 
    
         
            +
              var _this = this;
         
     | 
| 
      
 293 
     | 
    
         
            +
              $(this.tag).bind(bindEvent, function(event){ _this.checkValue(event); });
         
     | 
| 
      
 294 
     | 
    
         
            +
              $(this.tag).bind('keyup', function(event){ _this.reset(); });
         
     | 
| 
      
 295 
     | 
    
         
            +
            }
         
     | 
| 
      
 296 
     | 
    
         
            +
             
     | 
| 
      
 297 
     | 
    
         
            +
            Valitron.prototype = {
         
     | 
| 
      
 298 
     | 
    
         
            +
             
     | 
| 
      
 299 
     | 
    
         
            +
              checkValue:
         
     | 
| 
      
 300 
     | 
    
         
            +
                function(event, callback) {
         
     | 
| 
      
 301 
     | 
    
         
            +
                  var _this = this;
         
     | 
| 
      
 302 
     | 
    
         
            +
                  var path = (this.valibot.appUrl != null ? this.valibot.appUrl : '') +
         
     | 
| 
      
 303 
     | 
    
         
            +
                             '/' + this.valibot.pathPrefix +
         
     | 
| 
      
 304 
     | 
    
         
            +
                             '/' + this.model +
         
     | 
| 
      
 305 
     | 
    
         
            +
                             '/' + this.field +
         
     | 
| 
      
 306 
     | 
    
         
            +
                             (this.valibot.context != null ? ('/in/' + this.valibot.context) : '');
         
     | 
| 
      
 307 
     | 
    
         
            +
                  var val = this.tag.value;
         
     | 
| 
      
 308 
     | 
    
         
            +
                  if (this.tag.type.toLowerCase() == 'checkbox') val = this.tag.checked;
         
     | 
| 
      
 309 
     | 
    
         
            +
                  var params = {value: val};
         
     | 
| 
      
 310 
     | 
    
         
            +
                  if (this.valibot.dependents[this.field]) {
         
     | 
| 
      
 311 
     | 
    
         
            +
                    $(this.valibot.dependents[this.field]).each(function(i,dep) {
         
     | 
| 
      
 312 
     | 
    
         
            +
                      params[_this.model + '[' + dep + ']'] =
         
     | 
| 
      
 313 
     | 
    
         
            +
                        $('input[name="' + _this.model + '[' + dep + ']"], ' +
         
     | 
| 
      
 314 
     | 
    
         
            +
                          'select[name="' + _this.model + '[' + dep + ']"], ' +
         
     | 
| 
      
 315 
     | 
    
         
            +
                          'textarea[name="' + _this.model + '[' + dep + ']"]').val();
         
     | 
| 
      
 316 
     | 
    
         
            +
                    });
         
     | 
| 
      
 317 
     | 
    
         
            +
                  }
         
     | 
| 
      
 318 
     | 
    
         
            +
                  $.post(path, params, function(res){ _this.handleResponse(res, callback); },
         
     | 
| 
      
 319 
     | 
    
         
            +
                         this.valibot.appUrl != null ? 'jsonp' : 'json');
         
     | 
| 
      
 320 
     | 
    
         
            +
                },
         
     | 
| 
      
 321 
     | 
    
         
            +
             
     | 
| 
      
 322 
     | 
    
         
            +
              handleResponse:
         
     | 
| 
      
 323 
     | 
    
         
            +
                function(res, callback) {
         
     | 
| 
      
 324 
     | 
    
         
            +
             
     | 
| 
      
 325 
     | 
    
         
            +
                  // bad state -> good state
         
     | 
| 
      
 326 
     | 
    
         
            +
                  if (res == null && this.errorTag != null) {
         
     | 
| 
      
 327 
     | 
    
         
            +
                    var _this = this;
         
     | 
| 
      
 328 
     | 
    
         
            +
                    this.valibot.errorTagRemover(this.errorTag, this.valibot, function(ret){ _this.errorTag = null; }, this);
         
     | 
| 
      
 329 
     | 
    
         
            +
                    this.valibot.addValid(this);
         
     | 
| 
      
 330 
     | 
    
         
            +
                    if (callback != null) callback(true);
         
     | 
| 
      
 331 
     | 
    
         
            +
                    this.valid = true;
         
     | 
| 
      
 332 
     | 
    
         
            +
             
     | 
| 
      
 333 
     | 
    
         
            +
                  // null state -> good state
         
     | 
| 
      
 334 
     | 
    
         
            +
                  } else if (res == null && this.errorTag == null) {
         
     | 
| 
      
 335 
     | 
    
         
            +
                    this.valibot.addValid(this);
         
     | 
| 
      
 336 
     | 
    
         
            +
                    if (callback != null) callback(true);
         
     | 
| 
      
 337 
     | 
    
         
            +
                    this.valid = true;
         
     | 
| 
      
 338 
     | 
    
         
            +
             
     | 
| 
      
 339 
     | 
    
         
            +
                  // bad state -> bad state
         
     | 
| 
      
 340 
     | 
    
         
            +
                  } else if (res != null && res.error != null && this.errorTag != null) {
         
     | 
| 
      
 341 
     | 
    
         
            +
                    this.errorTag = this.valibot.errorTagTransformer(this.parseErrorStrings(res.error), this.errorTag, this.valibot, this);
         
     | 
| 
      
 342 
     | 
    
         
            +
                    this.valibot.addInvalid(this);
         
     | 
| 
      
 343 
     | 
    
         
            +
                    if (callback != null) callback(false);
         
     | 
| 
      
 344 
     | 
    
         
            +
                    this.valid = false;
         
     | 
| 
      
 345 
     | 
    
         
            +
             
     | 
| 
      
 346 
     | 
    
         
            +
                  // null state -> bad state
         
     | 
| 
      
 347 
     | 
    
         
            +
                  } else if (res != null && res.error != null && this.errorTag == null) {
         
     | 
| 
      
 348 
     | 
    
         
            +
                    this.errorTag = this.valibot.errorTagBuilder(this.parseErrorStrings(res.error), this.valibot, this);
         
     | 
| 
      
 349 
     | 
    
         
            +
                    this.valibot.errorTagPlacer(this.tag, this.errorTag, this.valibot, this);
         
     | 
| 
      
 350 
     | 
    
         
            +
                    this.valibot.addInvalid(this);
         
     | 
| 
      
 351 
     | 
    
         
            +
                    if (callback != null) callback(false);
         
     | 
| 
      
 352 
     | 
    
         
            +
                    this.valid = false;
         
     | 
| 
      
 353 
     | 
    
         
            +
                  }
         
     | 
| 
      
 354 
     | 
    
         
            +
                },
         
     | 
| 
      
 355 
     | 
    
         
            +
             
     | 
| 
      
 356 
     | 
    
         
            +
              parseErrorStrings:
         
     | 
| 
      
 357 
     | 
    
         
            +
                function(error) {
         
     | 
| 
      
 358 
     | 
    
         
            +
                  var es = '';
         
     | 
| 
      
 359 
     | 
    
         
            +
                  $(error).each(function(i, e) { es += e + '<br/>' });
         
     | 
| 
      
 360 
     | 
    
         
            +
                  return es.substring(0, es.length - 5); // remove last <br/>
         
     | 
| 
      
 361 
     | 
    
         
            +
                },
         
     | 
| 
      
 362 
     | 
    
         
            +
             
     | 
| 
      
 363 
     | 
    
         
            +
              reset:
         
     | 
| 
      
 364 
     | 
    
         
            +
                function() {
         
     | 
| 
      
 365 
     | 
    
         
            +
                  this.valibot.removeValid(this);
         
     | 
| 
      
 366 
     | 
    
         
            +
                  this.valid = false;
         
     | 
| 
      
 367 
     | 
    
         
            +
                }
         
     | 
| 
      
 368 
     | 
    
         
            +
             
     | 
| 
      
 369 
     | 
    
         
            +
            };
         
     | 
| 
      
 370 
     | 
    
         
            +
             
     | 
| 
      
 371 
     | 
    
         
            +
            // ---
         
     | 
| 
      
 372 
     | 
    
         
            +
             
     | 
| 
      
 373 
     | 
    
         
            +
            /* the Confirm-o-mat class. instantiated on form fields that are specified as
         
     | 
| 
      
 374 
     | 
    
         
            +
             * needing to match another field by an overseeing Valibot. handles the test
         
     | 
| 
      
 375 
     | 
    
         
            +
             * for equal values between fields.
         
     | 
| 
      
 376 
     | 
    
         
            +
             */
         
     | 
| 
      
 377 
     | 
    
         
            +
            function Confirmomat(id, things, valibot) {
         
     | 
| 
      
 378 
     | 
    
         
            +
              if ($('#' + id).length == 1 && $('#confirm_' + id).length == 1) {
         
     | 
| 
      
 379 
     | 
    
         
            +
                this.valid = false;
         
     | 
| 
      
 380 
     | 
    
         
            +
                this.tag = $('#confirm_' + id)[0];
         
     | 
| 
      
 381 
     | 
    
         
            +
                this.id = id;
         
     | 
| 
      
 382 
     | 
    
         
            +
                this.things = things;
         
     | 
| 
      
 383 
     | 
    
         
            +
                this.valibot = valibot;
         
     | 
| 
      
 384 
     | 
    
         
            +
                this.errorTag = null;
         
     | 
| 
      
 385 
     | 
    
         
            +
                var _this = this;
         
     | 
| 
      
 386 
     | 
    
         
            +
                $(this.tag).bind('blur', function(event){ _this.checkValue(event); });
         
     | 
| 
      
 387 
     | 
    
         
            +
                $(this.tag).bind('keyup', function(event){ _this.reset(); });
         
     | 
| 
      
 388 
     | 
    
         
            +
                $('#' + this.id).bind('keyup', function(event){ _this.reset(); });
         
     | 
| 
      
 389 
     | 
    
         
            +
              } else {
         
     | 
| 
      
 390 
     | 
    
         
            +
                // console.log('ERROR: matching fields not found or too many found.');
         
     | 
| 
      
 391 
     | 
    
         
            +
                return null;
         
     | 
| 
      
 392 
     | 
    
         
            +
              }
         
     | 
| 
      
 393 
     | 
    
         
            +
            }
         
     | 
| 
      
 394 
     | 
    
         
            +
             
     | 
| 
      
 395 
     | 
    
         
            +
            Confirmomat.prototype = {
         
     | 
| 
      
 396 
     | 
    
         
            +
             
     | 
| 
      
 397 
     | 
    
         
            +
              checkValue:
         
     | 
| 
      
 398 
     | 
    
         
            +
                function(event, callback) {
         
     | 
| 
      
 399 
     | 
    
         
            +
                  if ($('#' + this.id).val() == $(this.tag).val()) {
         
     | 
| 
      
 400 
     | 
    
         
            +
             
     | 
| 
      
 401 
     | 
    
         
            +
                    // bad state -> good state
         
     | 
| 
      
 402 
     | 
    
         
            +
                    if (this.errorTag != null) {
         
     | 
| 
      
 403 
     | 
    
         
            +
                      var _this = this;
         
     | 
| 
      
 404 
     | 
    
         
            +
                      this.valibot.errorTagRemover(this.errorTag, this.valibot, function(ret){ _this.errorTag = null; }, this);
         
     | 
| 
      
 405 
     | 
    
         
            +
                    }
         
     | 
| 
      
 406 
     | 
    
         
            +
             
     | 
| 
      
 407 
     | 
    
         
            +
                    // * state -> good state
         
     | 
| 
      
 408 
     | 
    
         
            +
                    this.valibot.addValid(this);
         
     | 
| 
      
 409 
     | 
    
         
            +
                    if (callback != null) callback(true);
         
     | 
| 
      
 410 
     | 
    
         
            +
                    this.valid = true;
         
     | 
| 
      
 411 
     | 
    
         
            +
             
     | 
| 
      
 412 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 413 
     | 
    
         
            +
             
     | 
| 
      
 414 
     | 
    
         
            +
                    // bad state -> bad state
         
     | 
| 
      
 415 
     | 
    
         
            +
                    if (this.errorTag != null) {
         
     | 
| 
      
 416 
     | 
    
         
            +
                      this.valibot.errorTagTransformer(this.things + " do not match.", this.errorTag, this.valibot, this);
         
     | 
| 
      
 417 
     | 
    
         
            +
             
     | 
| 
      
 418 
     | 
    
         
            +
                    // null state -> bad state
         
     | 
| 
      
 419 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 420 
     | 
    
         
            +
                      this.errorTag = this.valibot.errorTagBuilder(this.things + " do not match.", this.valibot, this);
         
     | 
| 
      
 421 
     | 
    
         
            +
                      this.valibot.errorTagPlacer(this.tag, this.errorTag, this.valibot, this);
         
     | 
| 
      
 422 
     | 
    
         
            +
                    }
         
     | 
| 
      
 423 
     | 
    
         
            +
             
     | 
| 
      
 424 
     | 
    
         
            +
                    // * state -> bad state
         
     | 
| 
      
 425 
     | 
    
         
            +
                    this.valibot.addInvalid(this);
         
     | 
| 
      
 426 
     | 
    
         
            +
                    if (callback != null) callback(false);
         
     | 
| 
      
 427 
     | 
    
         
            +
                    this.valid = false;
         
     | 
| 
      
 428 
     | 
    
         
            +
             
     | 
| 
      
 429 
     | 
    
         
            +
                  }
         
     | 
| 
      
 430 
     | 
    
         
            +
                },
         
     | 
| 
      
 431 
     | 
    
         
            +
             
     | 
| 
      
 432 
     | 
    
         
            +
              reset:
         
     | 
| 
      
 433 
     | 
    
         
            +
                function() {
         
     | 
| 
      
 434 
     | 
    
         
            +
                  // console.log('confirmomat resetting.');
         
     | 
| 
      
 435 
     | 
    
         
            +
                  this.valibot.removeValid(this);
         
     | 
| 
      
 436 
     | 
    
         
            +
                  this.valid = false;
         
     | 
| 
      
 437 
     | 
    
         
            +
                }
         
     | 
| 
      
 438 
     | 
    
         
            +
             
     | 
| 
      
 439 
     | 
    
         
            +
            };
         
     | 
| 
      
 440 
     | 
    
         
            +
             
     | 
| 
      
 441 
     | 
    
         
            +
            // ---
         
     | 
| 
      
 442 
     | 
    
         
            +
             
     | 
| 
      
 443 
     | 
    
         
            +
            /* the AgreePeeOh class. instantiated on checkboxes that are specified as
         
     | 
| 
      
 444 
     | 
    
         
            +
             * needing to be checked for form submission to be allowed.
         
     | 
| 
      
 445 
     | 
    
         
            +
             */
         
     | 
| 
      
 446 
     | 
    
         
            +
            function AgreePeeOh(id, things, valibot) {
         
     | 
| 
      
 447 
     | 
    
         
            +
              if ($('#' + id).length == 1) {
         
     | 
| 
      
 448 
     | 
    
         
            +
                this.valid = false;
         
     | 
| 
      
 449 
     | 
    
         
            +
                this.id = id;
         
     | 
| 
      
 450 
     | 
    
         
            +
                this.tag = $('#' + id)[0];
         
     | 
| 
      
 451 
     | 
    
         
            +
                this.things = things;
         
     | 
| 
      
 452 
     | 
    
         
            +
                this.valibot = valibot;
         
     | 
| 
      
 453 
     | 
    
         
            +
                this.errorTag = null;
         
     | 
| 
      
 454 
     | 
    
         
            +
                var _this = this;
         
     | 
| 
      
 455 
     | 
    
         
            +
                $(this.tag).bind('change', function(event){ _this.checkValue(event); });
         
     | 
| 
      
 456 
     | 
    
         
            +
              } else {
         
     | 
| 
      
 457 
     | 
    
         
            +
                return null;
         
     | 
| 
      
 458 
     | 
    
         
            +
              }
         
     | 
| 
      
 459 
     | 
    
         
            +
            }
         
     | 
| 
      
 460 
     | 
    
         
            +
             
     | 
| 
      
 461 
     | 
    
         
            +
            AgreePeeOh.prototype = {
         
     | 
| 
      
 462 
     | 
    
         
            +
             
     | 
| 
      
 463 
     | 
    
         
            +
              checkValue:
         
     | 
| 
      
 464 
     | 
    
         
            +
                function(event, callback) {
         
     | 
| 
      
 465 
     | 
    
         
            +
                  if ($('#' + this.id).attr('checked')) {
         
     | 
| 
      
 466 
     | 
    
         
            +
             
     | 
| 
      
 467 
     | 
    
         
            +
                    // bad state -> good state
         
     | 
| 
      
 468 
     | 
    
         
            +
                    if (this.errorTag != null) {
         
     | 
| 
      
 469 
     | 
    
         
            +
                      var _this = this;
         
     | 
| 
      
 470 
     | 
    
         
            +
                      this.valibot.errorTagRemover(this.errorTag, this.valibot, function(ret){ _this.errorTag = null; }, this);
         
     | 
| 
      
 471 
     | 
    
         
            +
                    }
         
     | 
| 
      
 472 
     | 
    
         
            +
             
     | 
| 
      
 473 
     | 
    
         
            +
                    // * state -> good state
         
     | 
| 
      
 474 
     | 
    
         
            +
                    this.valibot.addValid(this);
         
     | 
| 
      
 475 
     | 
    
         
            +
                    if (callback != null) callback(true);
         
     | 
| 
      
 476 
     | 
    
         
            +
                    this.valid = true;
         
     | 
| 
      
 477 
     | 
    
         
            +
             
     | 
| 
      
 478 
     | 
    
         
            +
                  } else {
         
     | 
| 
      
 479 
     | 
    
         
            +
             
     | 
| 
      
 480 
     | 
    
         
            +
                    // bad state -> bad state
         
     | 
| 
      
 481 
     | 
    
         
            +
                    if (this.errorTag != null) {
         
     | 
| 
      
 482 
     | 
    
         
            +
                      this.valibot.errorTagTransformer("You must agree to the " + this.things + ".", this.errorTag, this.valibot, this);
         
     | 
| 
      
 483 
     | 
    
         
            +
             
     | 
| 
      
 484 
     | 
    
         
            +
                    // null state -> bad state
         
     | 
| 
      
 485 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 486 
     | 
    
         
            +
                      this.errorTag = this.valibot.errorTagBuilder("You must agree to the " + this.things + ".", this.valibot, this);
         
     | 
| 
      
 487 
     | 
    
         
            +
                      this.valibot.errorTagPlacer(this.tag, this.errorTag, this.valibot, this);
         
     | 
| 
      
 488 
     | 
    
         
            +
                    }
         
     | 
| 
      
 489 
     | 
    
         
            +
             
     | 
| 
      
 490 
     | 
    
         
            +
                    // * state -> bad state
         
     | 
| 
      
 491 
     | 
    
         
            +
                    this.valibot.addInvalid(this);
         
     | 
| 
      
 492 
     | 
    
         
            +
                    if (callback != null) callback(false);
         
     | 
| 
      
 493 
     | 
    
         
            +
                    this.valid = false;
         
     | 
| 
      
 494 
     | 
    
         
            +
             
     | 
| 
      
 495 
     | 
    
         
            +
                  }
         
     | 
| 
      
 496 
     | 
    
         
            +
                },
         
     | 
| 
      
 497 
     | 
    
         
            +
             
     | 
| 
      
 498 
     | 
    
         
            +
              reset:
         
     | 
| 
      
 499 
     | 
    
         
            +
                function() {
         
     | 
| 
      
 500 
     | 
    
         
            +
                  this.valibot.removeValid(this);
         
     | 
| 
      
 501 
     | 
    
         
            +
                  this.valid = false;
         
     | 
| 
      
 502 
     | 
    
         
            +
                }
         
     | 
| 
      
 503 
     | 
    
         
            +
            };
         
     | 
    
        data/lib/valibot.rb
    ADDED
    
    | 
         @@ -0,0 +1,117 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # valibot.rb (c) 2011 kenichi nakamura (kenichi.nakamura@gmail.com)
         
     | 
| 
      
 2 
     | 
    
         
            +
            # 
         
     | 
| 
      
 3 
     | 
    
         
            +
            # easy automatic form field validation against datamapper models behind a sinatra app.
         
     | 
| 
      
 4 
     | 
    
         
            +
            # this is the helper module and Sinatra app class.
         
     | 
| 
      
 5 
     | 
    
         
            +
            # 
         
     | 
| 
      
 6 
     | 
    
         
            +
            # see ____ for details.  TODO
         
     | 
| 
      
 7 
     | 
    
         
            +
             
         
     | 
| 
      
 8 
     | 
    
         
            +
            module Valibot
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              JAVASCRIPT = File.join File.dirname(__FILE__), '..', 'js', 'valibot.js'
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              module Helpers
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                def self.registered app; app.helpers Valibot::Helpers; end
         
     | 
| 
      
 15 
     | 
    
         
            +
                def valibot_js; File.read Valibot::JAVASCRIPT; end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              class App < Sinatra::Base
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                before do
         
     | 
| 
      
 22 
     | 
    
         
            +
                  set_content_type
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                get '/valibot.js' do
         
     | 
| 
      
 26 
     | 
    
         
            +
                  content_type :js
         
     | 
| 
      
 27 
     | 
    
         
            +
                  cache_control :public, :max_age => 10 * 60
         
     | 
| 
      
 28 
     | 
    
         
            +
                  File.read Valibot::JAVASCRIPT
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                post '/:model/:field/in/:context' do
         
     | 
| 
      
 32 
     | 
    
         
            +
                  validate_field_value *parse(params)
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                post '/:model/in/:context' do
         
     | 
| 
      
 36 
     | 
    
         
            +
                  validate_model *parse(params)
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                post '/:model/:field' do
         
     | 
| 
      
 40 
     | 
    
         
            +
                  validate_field_value *parse(params)
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                post '/:model' do
         
     | 
| 
      
 44 
     | 
    
         
            +
                  validate_model *parse(params)
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                get '/:model/:field/in/:context' do
         
     | 
| 
      
 48 
     | 
    
         
            +
                  jsonp validate_field_value *parse(params)
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                get '/:model/in/:context' do
         
     | 
| 
      
 52 
     | 
    
         
            +
                  jsonp validate_model *parse(params)
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                get '/:model/:field' do
         
     | 
| 
      
 56 
     | 
    
         
            +
                  jsonp validate_field_value *parse(params)
         
     | 
| 
      
 57 
     | 
    
         
            +
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                get '/:model' do
         
     | 
| 
      
 60 
     | 
    
         
            +
                  jsonp validate_model *parse(params)
         
     | 
| 
      
 61 
     | 
    
         
            +
                end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                private
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                def parse params = {}
         
     | 
| 
      
 66 
     | 
    
         
            +
                  model_class_name = params[:model].camel_case
         
     | 
| 
      
 67 
     | 
    
         
            +
                  model_class = begin
         
     | 
| 
      
 68 
     | 
    
         
            +
                                  Kernel.const_get(model_class_name)
         
     | 
| 
      
 69 
     | 
    
         
            +
                                rescue NameError => e
         
     | 
| 
      
 70 
     | 
    
         
            +
                                  halt(Yajl.dump :error => e.message)
         
     | 
| 
      
 71 
     | 
    
         
            +
                                end
         
     | 
| 
      
 72 
     | 
    
         
            +
                  field_sym = params[:field] ? params[:field].to_sym : nil
         
     | 
| 
      
 73 
     | 
    
         
            +
                  context = params[:context] ? params[:context].to_sym : :default
         
     | 
| 
      
 74 
     | 
    
         
            +
                  dependents = params[params[:model]]
         
     | 
| 
      
 75 
     | 
    
         
            +
                  [model_class, field_sym, context, dependents].compact
         
     | 
| 
      
 76 
     | 
    
         
            +
                end
         
     | 
| 
      
 77 
     | 
    
         
            +
                
         
     | 
| 
      
 78 
     | 
    
         
            +
                def validate_field_value model = nil, field = nil, context = :default, dependents = {}
         
     | 
| 
      
 79 
     | 
    
         
            +
                  if model && model.included_modules.include?(DataMapper::Resource)
         
     | 
| 
      
 80 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 81 
     | 
    
         
            +
                      if model.properties.map(&:name).include?(field) or model.new.__send__(field).kind_of?(DataMapper::Collection)
         
     | 
| 
      
 82 
     | 
    
         
            +
                        obj = model.new dependents.merge field => params['value']
         
     | 
| 
      
 83 
     | 
    
         
            +
                        Yajl.dump :error => obj.errors[field] if !obj.valid?(context) && obj.errors.keys.include?(field)
         
     | 
| 
      
 84 
     | 
    
         
            +
                      else
         
     | 
| 
      
 85 
     | 
    
         
            +
                        Yajl.dump :error => "Invalid field: #{params[:field]}"
         
     | 
| 
      
 86 
     | 
    
         
            +
                      end
         
     | 
| 
      
 87 
     | 
    
         
            +
                    rescue NoMethodError => e
         
     | 
| 
      
 88 
     | 
    
         
            +
                      Yajl.dump :error => "Invalid field: #{params[:field]}"
         
     | 
| 
      
 89 
     | 
    
         
            +
                    end
         
     | 
| 
      
 90 
     | 
    
         
            +
                  else
         
     | 
| 
      
 91 
     | 
    
         
            +
                    Yajl.dump :error => "Invalid model: #{params[:model].camel_case}"
         
     | 
| 
      
 92 
     | 
    
         
            +
                  end
         
     | 
| 
      
 93 
     | 
    
         
            +
                end
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                def validate_model model = nil, context = :default
         
     | 
| 
      
 96 
     | 
    
         
            +
                  if model && model.included_modules.include?(DataMapper::Resource)
         
     | 
| 
      
 97 
     | 
    
         
            +
                    obj = model.new params[params[:model]]
         
     | 
| 
      
 98 
     | 
    
         
            +
                    unless obj.valid?(context)
         
     | 
| 
      
 99 
     | 
    
         
            +
                      Yajl.dump :error => obj.errors.to_hash
         
     | 
| 
      
 100 
     | 
    
         
            +
                    end
         
     | 
| 
      
 101 
     | 
    
         
            +
                  else
         
     | 
| 
      
 102 
     | 
    
         
            +
                    Yajl.dump :error => "Invalid model: #{params[:model].camel_case}"
         
     | 
| 
      
 103 
     | 
    
         
            +
                  end
         
     | 
| 
      
 104 
     | 
    
         
            +
                end
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                def set_content_type
         
     | 
| 
      
 107 
     | 
    
         
            +
                  content_type (params['callback'] ? :js : :json)
         
     | 
| 
      
 108 
     | 
    
         
            +
                end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                def jsonp json = ''
         
     | 
| 
      
 111 
     | 
    
         
            +
                  return json unless params['callback']
         
     | 
| 
      
 112 
     | 
    
         
            +
                  params['callback'] + "(#{json})"
         
     | 
| 
      
 113 
     | 
    
         
            +
                end
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
              end
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
            end
         
     | 
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,90 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification 
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: valibot
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version 
         
     | 
| 
      
 4 
     | 
    
         
            +
              prerelease: 
         
     | 
| 
      
 5 
     | 
    
         
            +
              version: 0.2.5
         
     | 
| 
      
 6 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 7 
     | 
    
         
            +
            authors: 
         
     | 
| 
      
 8 
     | 
    
         
            +
            - Kenichi Nakamura
         
     | 
| 
      
 9 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 10 
     | 
    
         
            +
            bindir: bin
         
     | 
| 
      
 11 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            date: 2011-08-02 00:00:00 Z
         
     | 
| 
      
 14 
     | 
    
         
            +
            dependencies: 
         
     | 
| 
      
 15 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency 
         
     | 
| 
      
 16 
     | 
    
         
            +
              name: dm-core
         
     | 
| 
      
 17 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 18 
     | 
    
         
            +
              requirement: &id001 !ruby/object:Gem::Requirement 
         
     | 
| 
      
 19 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 20 
     | 
    
         
            +
                requirements: 
         
     | 
| 
      
 21 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 22 
     | 
    
         
            +
                  - !ruby/object:Gem::Version 
         
     | 
| 
      
 23 
     | 
    
         
            +
                    version: 1.0.0
         
     | 
| 
      
 24 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 25 
     | 
    
         
            +
              version_requirements: *id001
         
     | 
| 
      
 26 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency 
         
     | 
| 
      
 27 
     | 
    
         
            +
              name: dm-validations
         
     | 
| 
      
 28 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 29 
     | 
    
         
            +
              requirement: &id002 !ruby/object:Gem::Requirement 
         
     | 
| 
      
 30 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 31 
     | 
    
         
            +
                requirements: 
         
     | 
| 
      
 32 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 33 
     | 
    
         
            +
                  - !ruby/object:Gem::Version 
         
     | 
| 
      
 34 
     | 
    
         
            +
                    version: 1.0.0
         
     | 
| 
      
 35 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 36 
     | 
    
         
            +
              version_requirements: *id002
         
     | 
| 
      
 37 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency 
         
     | 
| 
      
 38 
     | 
    
         
            +
              name: sinatra
         
     | 
| 
      
 39 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 40 
     | 
    
         
            +
              requirement: &id003 !ruby/object:Gem::Requirement 
         
     | 
| 
      
 41 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 42 
     | 
    
         
            +
                requirements: 
         
     | 
| 
      
 43 
     | 
    
         
            +
                - - ">="
         
     | 
| 
      
 44 
     | 
    
         
            +
                  - !ruby/object:Gem::Version 
         
     | 
| 
      
 45 
     | 
    
         
            +
                    version: 1.1.0
         
     | 
| 
      
 46 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 47 
     | 
    
         
            +
              version_requirements: *id003
         
     | 
| 
      
 48 
     | 
    
         
            +
            description: 
         
     | 
| 
      
 49 
     | 
    
         
            +
            email: 
         
     | 
| 
      
 50 
     | 
    
         
            +
            - kenichi.nakamura@gmail.com
         
     | 
| 
      
 51 
     | 
    
         
            +
            executables: []
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
            extra_rdoc_files: []
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
            files: 
         
     | 
| 
      
 58 
     | 
    
         
            +
            - lib/valibot.rb
         
     | 
| 
      
 59 
     | 
    
         
            +
            - js/valibot.js
         
     | 
| 
      
 60 
     | 
    
         
            +
            - LICENSE
         
     | 
| 
      
 61 
     | 
    
         
            +
            - README.md
         
     | 
| 
      
 62 
     | 
    
         
            +
            homepage: https://github.com/kenichi/valibot
         
     | 
| 
      
 63 
     | 
    
         
            +
            licenses: []
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 66 
     | 
    
         
            +
            rdoc_options: []
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
            require_paths: 
         
     | 
| 
      
 69 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 70 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement 
         
     | 
| 
      
 71 
     | 
    
         
            +
              none: false
         
     | 
| 
      
 72 
     | 
    
         
            +
              requirements: 
         
     | 
| 
      
 73 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 74 
     | 
    
         
            +
                - !ruby/object:Gem::Version 
         
     | 
| 
      
 75 
     | 
    
         
            +
                  version: "0"
         
     | 
| 
      
 76 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement 
         
     | 
| 
      
 77 
     | 
    
         
            +
              none: false
         
     | 
| 
      
 78 
     | 
    
         
            +
              requirements: 
         
     | 
| 
      
 79 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 80 
     | 
    
         
            +
                - !ruby/object:Gem::Version 
         
     | 
| 
      
 81 
     | 
    
         
            +
                  version: 1.3.4
         
     | 
| 
      
 82 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
            rubyforge_project: valibot
         
     | 
| 
      
 85 
     | 
    
         
            +
            rubygems_version: 1.8.6
         
     | 
| 
      
 86 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 87 
     | 
    
         
            +
            specification_version: 3
         
     | 
| 
      
 88 
     | 
    
         
            +
            summary: Automatic field validation for forms backed by  DataMapper models through Sinatra.
         
     | 
| 
      
 89 
     | 
    
         
            +
            test_files: []
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     |