Constraints jQuery Plugin


/ Published in: JavaScript
Save to your folder(s)

Constraints plugin (requires annotation plugin).

This is the second draft version that has been severly refactoed both internally and externally.


Copy this code and paste it in your HTML
  1. /*---------------------------------------------------------------------------------
  2.  *
  3.  * Process Constraints jQuery Plugin
  4.  *
  5.  *---------------------------------------------------------------------------------
  6.  *
  7.  * This plugin is responsible for apply constraints to a target form. It
  8.  * will examin each fiels annotations to find @Constraints annotation and
  9.  * appply the requested constraints to the field. An number of configuration
  10.  * options are available (see below)
  11.  *
  12.  * @author James Hughes
  13.  *
  14.  * -------------------------------------------------------------------------------
  15.  * 24/10/2008 - Initial Version
  16.  * -------------------------------------------------------------------------------
  17.  * 28/10/2008 - Second Draft: Major Internal Refactoring. Introduced new public
  18.  * API's for working with constratins and messages. Added the
  19.  * ability to remove constraints singularly and globally as well as
  20.  * actually uninstall the plugin.
  21.  * -------------------------------------------------------------------------------
  22.  *///------------------------------------------------------------------------------
  23. (function($){
  24.  
  25. /*-----------------------------------------------------------------------------
  26.   *
  27.   * isEmpty Utility Function
  28.   *
  29.   *-----------------------------------------------------------------------------
  30.   *
  31.   * Utility function that ensures a string is either null or an empty string.
  32.   *
  33.   * @plugin
  34.   * @param v - the value to check for emptiness
  35.   *
  36.   *///--------------------------------------------------------------------------
  37. $.isEmpty = function(v){
  38. return !v || v == "" || $.trim(v) == "";
  39. };
  40.  
  41. /*-----------------------------------------------------------------------------
  42.   *
  43.   * Process Constraints Plugin
  44.   *
  45.   *-----------------------------------------------------------------------------
  46.   *
  47.   * Extend the jQuery Object to provide a utility function that will perform
  48.   * the constraint application functionality to the form passed in
  49.   *
  50.   * @plugin
  51.   * @param o - custom options object that accepts
  52.   *
  53.   * customMessages: map of custom constraint messages
  54.   * customConstraints: map of custom constraints to apply
  55.   * constraintTrigger: event that triggers contraint tests
  56.   * stopOnFirst: determines if we break on first error
  57.   * errorFn: error handler fn(field, failed)
  58.   * successFn: called when all constraints pass
  59.   *
  60.   *///--------------------------------------------------------------------------
  61. $.fn.constrain = function(o){
  62.  
  63. /*-------------------------------------------------------------------------
  64.   *
  65.   * Apply Options
  66.   *
  67.   *-------------------------------------------------------------------------
  68.   *
  69.   * Merge the default and custom options resulting in a specific options
  70.   * map for this function call.
  71.   *
  72.   *///----------------------------------------------------------------------
  73. var options = $.extend({},defaultOptions, o);
  74.  
  75. /*-------------------------------------------------------------------------
  76.   *
  77.   * Messages
  78.   *
  79.   *-------------------------------------------------------------------------
  80.   *
  81.   * Constraint messages are built up from a set of defaults. Merged with
  82.   * a set of user defined messages. When a constraint fails the first
  83.   * message looked up is the id of the field followed by the name of the
  84.   * constraint eg - txtName.mandatory. If this does not exist or if the
  85.   * field does not have an id it will ue the default message.
  86.   *
  87.   *///----------------------------------------------------------------------
  88. if(o.customMessages){
  89. MessageSource.addMessages(o.customMessages);
  90. }
  91.  
  92. /*-------------------------------------------------------------------------
  93.   *
  94.   * Create Available Constraints
  95.   *
  96.   *-------------------------------------------------------------------------
  97.   *
  98.   * Represents a map of all available constraints that can be applied to
  99.   * a field. This is created by merging customConstraints map from the
  100.   * passed options with the default constraints.
  101.   *
  102.   *///----------------------------------------------------------------------
  103. if(options.customConstraints){
  104. ConstraintService.registerAll(options.customConstraints);
  105. }
  106.  
  107. /*-------------------------------------------------------------------------
  108.   *
  109.   * Apply Constraints
  110.   *
  111.   *-------------------------------------------------------------------------
  112.   *
  113.   * This section discovers the required constraints on a per field basis
  114.   * and applies the behaviour to the field
  115.   *
  116.   *///----------------------------------------------------------------------
  117. return this.each(function(){
  118.  
  119. /*---------------------------------------------------------------------
  120.   *
  121.   * No Constraint Failover
  122.   *
  123.   *---------------------------------------------------------------------
  124.   *
  125.   * Most of this API is open to the public therefore open to the
  126.   * irresponsible, ignorant, clueless and just plain stupid. We need
  127.   * to cater for as much worst case edge cases as we can without
  128.   * making the good people suffer. Exit if no constraints defined on
  129.   * element.
  130.   *
  131.   *///------------------------------------------------------------------
  132. if(!$(this).annotations("@Constraints")[0]){ return undefined };
  133.  
  134. /*---------------------------------------------------------------------
  135.   *
  136.   * Constraint Discovery
  137.   *
  138.   *---------------------------------------------------------------------
  139.   *
  140.   * We extract the requested constraints via annotations on the field
  141.   * and build a map of applicable constraints which is set as a data
  142.   * item on the element. At the same time we also set another map of
  143.   * constratint data that can be passed into the constraint test
  144.   * function
  145.   *
  146.   *///------------------------------------------------------------------
  147. var requestedConstraints = $(this).annotations("@Constraints")[0].data;
  148. for(constraint in requestedConstraints){
  149. /* filter out falsey values */
  150. if(requestedConstraints[constraint]){
  151. ConstraintService.bind($(this), constraint, requestedConstraints[constraint]);
  152. }
  153. }
  154.  
  155. /*---------------------------------------------------------------------
  156.   *
  157.   * Event Binding
  158.   *
  159.   *---------------------------------------------------------------------
  160.   *
  161.   * Bind the Constraint Trigger Callback to the trigger event. Also
  162.   * we are passing in the options object so we still have access to
  163.   * the options object. Done in this way to ensure we can unbind the
  164.   * callback function if the user wants.
  165.   *
  166.   *///------------------------------------------------------------------
  167. $(this).bind((this.constraintTrigger = options.constraintTrigger), options, constraintCallback);
  168. });
  169. }
  170.  
  171. /*-----------------------------------------------------------------------------
  172.   *
  173.   * Unconstrain Plugin
  174.   *
  175.   *-----------------------------------------------------------------------------
  176.   *
  177.   * Removes any current constraints applied to the passed in fields as well
  178.   * as removing data caches and constraint events
  179.   *
  180.   * @plugin
  181.   *
  182.   *///--------------------------------------------------------------------------
  183. $.fn.unconstrain = function(){
  184. return this.each(function(){ ConstraintService.unconstrain(this); });
  185. }
  186.  
  187. /*-----------------------------------------------------------------------------
  188.   *
  189.   * Unconstrain Plugin
  190.   *
  191.   *-----------------------------------------------------------------------------
  192.   *
  193.   * Helper function to remove all constraints form an entire form.
  194.   *
  195.   * @plugin
  196.   * @param frm - form/id/jQuery representing the form to process
  197.   *
  198.   *///--------------------------------------------------------------------------
  199. $.unconstrainForm = function(frm){
  200. ConstraintService.unconstrainAll($(frm)[0]);
  201. }
  202.  
  203. /*-----------------------------------------------------------------------------
  204.   *
  205.   * Process Constraints Plugin
  206.   *
  207.   *-----------------------------------------------------------------------------
  208.   *
  209.   * Extend the jQuery Object to provide a utility function that will perform
  210.   * the constraint application functionality to the form passed in
  211.   *
  212.   * @plugin
  213.   * @param frm - form/id/jQuery representing the form to process
  214.   * @param o - custom options object that accepts
  215.   *
  216.   * customMessages: map of custom constraint messages
  217.   * customConstraints: map of custom constraints to apply
  218.   * constraintTrigger: event that triggers contraint tests
  219.   * stopOnFirst: determines if we break on first error
  220.   * errorFn: error handler fn(field, failed)
  221.   * successFn: called when all constraints pass
  222.   *
  223.   *///--------------------------------------------------------------------------
  224. $.constrainForm = function(frm,o){
  225. $.annotated("@Constraints", $(frm)[0]).constrain(o);
  226. }
  227.  
  228. /*-----------------------------------------------------------------------------
  229.   *
  230.   * Default Options
  231.   *
  232.   *-----------------------------------------------------------------------------
  233.   *
  234.   * This map represents the global default options that should be used
  235.   * when applying constraints. They can be overridden via custom maps
  236.   * passed into the functions.
  237.   *
  238.   *///--------------------------------------------------------------------------
  239. var defaultOptions = {
  240. customMessages : {}, // map of custom constraint messages
  241. customConstraints : {}, // map of custom constraints to apply
  242. constraintTrigger : 'blur', // event that triggers contraint tests
  243. stopOnFirst : false, // determines if we break on first error
  244. errorFn : function(){}, // error handling callback
  245. successfn : function(){} // successfull callback
  246. }
  247.  
  248. /*-----------------------------------------------------------------------------
  249.   *
  250.   * Constraint Service
  251.   *
  252.   *-----------------------------------------------------------------------------
  253.   *
  254.   * Singleton class used to handles page level contraint testing and
  255.   * registration.
  256.   *
  257.   * @constructor
  258.   *
  259.   *///--------------------------------------------------------------------------
  260. var ConstraintService = function(){
  261.  
  262. /*-------------------------------------------------------------------------
  263.   *
  264.   * Default Constraints
  265.   *
  266.   *-------------------------------------------------------------------------
  267.   *
  268.   * Represents a map of all available constraints that can be applied to a
  269.   * field. This is merged with a custom constraints that can be declared
  270.   * via the options object to provide a list of all available constraints
  271.   * that can be applied to the fields
  272.   *
  273.   *///----------------------------------------------------------------------
  274. var defaultConstraints = {
  275. alpha:function(v){
  276. return $.isEmpty(v) || /^[a-z]*$/i.test(v);
  277. },
  278. alphanumeric:function(v){
  279. return $.isEmpty(v) || /^[a-z0-9]*$/i.test(v);
  280. },
  281. mandatory:function(v){
  282. return !$.isEmpty(v);
  283. },
  284. creditCard:function(v){
  285. return $.isEmpty(v) || /^\d{4}-?\d{4}-?\d{4}-?\d{4}$/.test(v);
  286. },
  287. currency:function(v){
  288. return $.isEmpty(v) || /^(\d{1,3},?(\d{3},?)*\d{3}(\.\d{0,2})?|\d{1,3}(\.\d{0,2})?|\.\d{1,2}?)$/.test(v);
  289. },
  290. digitsOnly:function(v){
  291. return $.isEmpty(v) || /^[0-9]*$/.test(v);
  292. },
  293. email:function(v){
  294. return $.isEmpty(v) || /^(("[\w-\s]+")|([\w-]+(?:\.[\w-]+)*)|("[\w-\s]+")([\w-]+(?:\.[\w-]+)*))(@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$)|(@\[?((25[0-5]\.|2[0-4][0-9]\.|1[0-9]{2}\.|[0-9]{1,2}\.))((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\.){2}(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[0-9]{1,2})\]?$)/i.test(v);
  295. },
  296. inList:function(v,l){
  297. return $.isEmpty(v) || $.inArray(v,l) > -1;
  298. },
  299. ip:function(v){
  300. return $.isEmpty(v) || /^(([01]?\d?\d|2[0-4]\d|25[0-5])\.){3}([01]?\d?\d|2[0-4]\d|25[0-5])$/.test(v);
  301. },
  302. matches:function(v,e){
  303. return $.isEmpty(v) || (e.constructor === RegExp) ? e.test(v) : r == v;
  304. },
  305. max:function(v,m){
  306. return $.isEmpty(v) || (!isNaN(v) && parseInt(v) <= m);
  307. },
  308. maxSize:function(v,m){
  309. return $.isEmpty(v) || v.length <= m;
  310. },
  311. min:function(v,m){
  312. return $.isEmpty(v) || (!isNaN(v) && parseInt(v) >= m);
  313. },
  314. minSize:function(v,m){
  315. return $.isEmpty(v) || v.length >= m;
  316. },
  317. notEqual:function(v,n){
  318. return $.isEmpty(v) || v != n;
  319. },
  320. range:function(v,d,e){
  321.  
  322. if($.isEmpty(v)){ return true; }
  323.  
  324. switch($(e).data("constraints").type){
  325. case 'boolean': return /^(true)|(false)$/i.test(v);
  326. case 'date': return !isNaN(Date.parse(v)) && Date.parse(v) >= Date.parse(d.start) && Date.parse(v) <= Date.parse(d.end);
  327. case 'float': return !isNaN(v) && parseFloat(v) >= d.start && parseFloat(v) <= d.end;
  328. case 'int': return !isNaN(v) && parseInt(v) >= d.start && parseInt(v) <= d.end;
  329. case 'string':
  330. default: return v >= d.start && v <= d.end;
  331. }
  332. },
  333. size:function(v,d){
  334. return $.isEmpty(v) || ((d.end) ? v.length >= d.start && v.length <= d.end : v.length === d.start);
  335. },
  336. type:function(v,t){
  337.  
  338. if($.isEmpty(v)){ return true; }
  339.  
  340. switch(t){
  341. case 'boolean': return /^(true)|(false)$/i.test(v);
  342. case 'date': return !isNaN(Date.parse(v));
  343. case 'float': return !isNaN(parseFloat(v));
  344. case 'int': return !isNaN(parseInt(v)) && /^-?[0-9]+$/.test(v);
  345. case 'string': return v.constructor === String;
  346. default: throw(t + " is not a valid field type");
  347. }
  348. },
  349. url:function(v){
  350. return $.isEmpty(v) || /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/.test(v);
  351. },
  352. validator:function(v,f,e){
  353. return $.isEmpty(v) || f(v,e);
  354. }
  355. };
  356.  
  357. /*-------------------------------------------------------------------------
  358.   *
  359.   * Manipulate Constraints
  360.   *
  361.   *-------------------------------------------------------------------------
  362.   *
  363.   * Helper function that wraps the default pre and post functionality.
  364.   *
  365.   * Accepts a target element and a processing function that accepts the
  366.   * constraint cache and constratin data cache for that element and allows
  367.   * you to edit it before setting the values back to the cache.
  368.   *
  369.   *///----------------------------------------------------------------------
  370. var manipulateConstraints = function(el, f){
  371.  
  372. var c = $(el).data("constraints") || {};
  373. var cd = $(el).data("constraint-data") || {};
  374.  
  375. f(c, cd);
  376.  
  377. $(el).data("constraints", c);
  378. $(el).data("constraint-data", cd);
  379. };
  380.  
  381. /*-------------------------------------------------------------------------
  382.   *
  383.   * Has Constraints?
  384.   *
  385.   *-------------------------------------------------------------------------
  386.   *
  387.   * Helper function that d
  388.   *
  389.   *///----------------------------------------------------------------------
  390. var hasConstraint = function(el,constraint){
  391. return !!($(el).data("constraints") || {})[constraint];
  392. }
  393.  
  394. /*-------------------------------------------------------------------------
  395.   *
  396.   * Initialisation
  397.   *
  398.   *-------------------------------------------------------------------------
  399.   *
  400.   * Set up the initial state of the Constraint Service.
  401.   *
  402.   *///----------------------------------------------------------------------
  403. var availableConstraints = $.extend({},defaultConstraints);
  404.  
  405. /*-------------------------------------------------------------------------
  406.   *
  407.   * Constraint Service Public API
  408.   *
  409.   *-------------------------------------------------------------------------
  410.   *
  411.   * Publically available functions for the Constraints Service
  412.   *
  413.   *///----------------------------------------------------------------------
  414. return {
  415.  
  416. /*---------------------------------------------------------------------
  417.   *
  418.   * Register Constraint
  419.   *
  420.   *---------------------------------------------------------------------
  421.   *
  422.   * Registers a single constraint with the Constraint Service so it
  423.   * can be used going forward by fields
  424.   *
  425.   * @param name - name of the constraint to apply
  426.   * @param test - test function for constraint
  427.   *
  428.   *///------------------------------------------------------------------
  429. register: function(name, test){
  430. availableConstraints[name] = test;
  431. },
  432.  
  433. /*---------------------------------------------------------------------
  434.   *
  435.   * Register Constraints
  436.   *
  437.   *---------------------------------------------------------------------
  438.   *
  439.   * Registers a group of constraints at one time. Takes a map of name
  440.   * function pairs and applies it to the available constraints
  441.   *
  442.   * @param constraints - {name:test,...} map of constraints
  443.   *
  444.   *///------------------------------------------------------------------
  445. registerAll: function(constraints){
  446. $.extend(availableConstraints, constraints);
  447. },
  448.  
  449. /*---------------------------------------------------------------------
  450.   *
  451.   * Get Constraint Test
  452.   *
  453.   *---------------------------------------------------------------------
  454.   *
  455.   * Returns a, if defined, the associated constratin test funciton
  456.   * otherwise it returns undefined.
  457.   *
  458.   * @param name - name of constaint to return
  459.   *
  460.   *///------------------------------------------------------------------
  461. get: function(name){
  462. return availableConstraints[name];
  463. },
  464.  
  465. /*---------------------------------------------------------------------
  466.   *
  467.   * Bind Constraint
  468.   *
  469.   *---------------------------------------------------------------------
  470.   *
  471.   * Performs constraint binding work on the passed in element. More
  472.   * specifically it loads and cahces the constraint and data on to the
  473.   * element so the global constraint function can manipulate it.
  474.   *
  475.   * @param element - target element to bind constraint to
  476.   * @param constraint - name/id of constraint to apply
  477.   * @param data - constratin data applicable to bound contraint
  478.   *
  479.   *///------------------------------------------------------------------
  480. bind: function(element, constraint, data){
  481. manipulateConstraints(element, function(constraints,constraintData){
  482. constraints[constraint] = ConstraintService.get(constraint);
  483. constraintData[constraint] = data;
  484. });
  485. },
  486.  
  487. /*---------------------------------------------------------------------
  488.   *
  489.   * Unbind Constraint
  490.   *
  491.   *---------------------------------------------------------------------
  492.   *
  493.   * Removes the constraint from the passed in element including data
  494.   *
  495.   * @param element - target element to remove constraint from
  496.   * @param constraint - name/id of constraint to remover
  497.   *
  498.   *///------------------------------------------------------------------
  499. unbind: function(element, constraint){
  500. manipulateConstraints(element, function(constraints,constraintData){
  501. delete(constraints[constraint]);
  502. delete(constraintData[constraint]);
  503. });
  504. },
  505.  
  506. /*---------------------------------------------------------------------
  507.   *
  508.   * Unbind All Constraints
  509.   *
  510.   *---------------------------------------------------------------------
  511.   *
  512.   * Globally unbinds constraint from all elements under the passed in
  513.   * root element (document is default).
  514.   *
  515.   * @param constraint - name/id of constraint to remove
  516.   * @param root - the root element to begin removal
  517.   *
  518.   *///------------------------------------------------------------------
  519. unbindAll : function(constraint, root){
  520. $.annotated("@Constraints", root).each(function(){
  521. if(hasConstraint(this,constraint)){
  522. ConstraintService.unbind(this, constraint);
  523. }
  524. });
  525. },
  526.  
  527. /*---------------------------------------------------------------------
  528.   *
  529.   * Unconstrain
  530.   *
  531.   *---------------------------------------------------------------------
  532.   *
  533.   * Removes constraint related data and events from the element
  534.   *
  535.   * @param root - the root element to begin removal
  536.   *
  537.   *///------------------------------------------------------------------
  538. unconstrain : function(el){
  539.  
  540. /* remove data */
  541. $(el).removeData("constraints");
  542. $(el).removeData("constraint-data");
  543.  
  544. /* unbind events */
  545. $(el).unbind(this.constraintTrigger, constraintCallback);
  546.  
  547. /* delete dom expando's */
  548. delete(el.constraintTrigger);
  549. },
  550.  
  551. /*---------------------------------------------------------------------
  552.   *
  553.   * Unconstrain All
  554.   *
  555.   *---------------------------------------------------------------------
  556.   *
  557.   * Globally destroys all constraints including data and events
  558.   *
  559.   * @param root - the root element to begin removal
  560.   *
  561.   *///------------------------------------------------------------------
  562. unconstrainAll : function(root){
  563. $.annotated("@Constraints", root).each(function(){
  564. ConstraintService.unconstrain(this)
  565. });
  566. }
  567. }
  568. }();
  569.  
  570. /*-----------------------------------------------------------------------------
  571.   *
  572.   * Message Source
  573.   *
  574.   *-----------------------------------------------------------------------------
  575.   *
  576.   * This Singleton encapsulates message source functionaltiy related
  577.   * specifically to loading messages for constraints.
  578.   *
  579.   * @constructor
  580.   *
  581.   *///--------------------------------------------------------------------------
  582. var MessageSource = (function(){
  583.  
  584. /*-------------------------------------------------------------------------
  585.   *
  586.   * Default Messages
  587.   *
  588.   *-------------------------------------------------------------------------
  589.   *
  590.   * This map the default messages that should be applied to a
  591.   * field when there are no custom messages to be applied to a failed
  592.   * constraint.
  593.   *
  594.   *///----------------------------------------------------------------------
  595. var defaultMessages = {
  596. alpha : "${field} must be composed of alpha characters A-Z,a-z",
  597. alphaNumeric : "${field} must be composed of alphanumeric characters A-Z,a-z,0-9",
  598. mandatory : "${field} is a mandatory field",
  599. creditCard : "${field} must be a valid credit card number",
  600. currency : "${value} is not a valid currency format",
  601. digitsOnly : "${field} must be composed of only digits",
  602. email : "${field} must be a valid email address",
  603. indexed : "${field} is indexed and no indexed fields contain values",
  604. inList : "${field} must be one of the following values: ${data}",
  605. ip : "${field} must be a valid IP Address",
  606. matches : "${field} does not match the required expression",
  607. max : "${field} cannot exceed ${data}",
  608. maxSize : "${field} cannot exceeds the maximum length (${data})",
  609. min : "${field} cannot be less than ${data}",
  610. minSize : "${field} cannot is less than the minimum length (${data})",
  611. notEqual : "${field} cannot have the value of ${value}",
  612. range : "${field} must be between ${start} and ${end}",
  613. size : "${field} is not the stated size",
  614. type : "${field} is not the correct type (${data})",
  615. url : "${field} must be a valid URL",
  616. validator : "${field} has failed custom validation"
  617. };
  618.  
  619. var ms = {"default":defaultMessages}
  620.  
  621. /*-------------------------------------------------------------------------
  622.   *
  623.   * Format Message Function
  624.   *
  625.   *-------------------------------------------------------------------------
  626.   *
  627.   * Private function to apply data to a templated message
  628.   *
  629.   * @param m - the unformatted message
  630.   * @param e - the element in question
  631.   * @param k - the key for the data-cache to get extra data from
  632.   * @param d - the data-cache for extra template options
  633.   *
  634.   *///----------------------------------------------------------------------
  635. var formatMessage = function(m,e,k,d){
  636.  
  637. var cdata = ((d) ? d[k] : null) || {};
  638.  
  639. if(cdata.constructor !== Object){
  640. cdata = {data : cdata}
  641. }
  642.  
  643. var data = $.extend({}, {field:e.id || e.name, value: $(e).val()}, cdata), fm = m;
  644.  
  645. for(d in data){
  646. fm = fm.replace(new RegExp('\\${'+d+'}','g'), data[d].toString());
  647. }
  648.  
  649. return fm;
  650. };
  651.  
  652. return {
  653.  
  654. /*---------------------------------------------------------------------
  655.   *
  656.   * Get Message Function
  657.   *
  658.   *---------------------------------------------------------------------
  659.   *
  660.   * This function interrogates a passed element and returns a the
  661.   * message that most closely matches the proximity. If
  662.   * <element_name/element_id>.<k> exists then this is returned as an
  663.   * evaluated message. Otherwise it looks up the global default
  664.   * message default.<key>.
  665.   *
  666.   * @param e - source element
  667.   * @param k - key for the message
  668.   *
  669.   *///------------------------------------------------------------------
  670. getMessage:function(e,k){
  671. return formatMessage(((e && e.id && ms[e.id])?ms[e.id][k]:ms["default"][k]) || "",e,k,(e)?$(e).data("constaint-data"):null);
  672. },
  673.  
  674. /*---------------------------------------------------------------------
  675.   *
  676.   * Add Messages Function
  677.   *
  678.   *---------------------------------------------------------------------
  679.   *
  680.   * Add new custom messages to the messageSource
  681.   *
  682.   *///------------------------------------------------------------------
  683. addMessages:function(c){
  684. ms = $.extend(true,ms,c);
  685. },
  686.  
  687. /*---------------------------------------------------------------------
  688.   *
  689.   * Add Message Function
  690.   *
  691.   *---------------------------------------------------------------------
  692.   *
  693.   * Add a new custom message to the messageSource
  694.   *
  695.   *///------------------------------------------------------------------
  696. addMessage: function(namespace, msg){
  697. MessageSource.addMessages({namespace:msg});
  698. },
  699.  
  700. /*---------------------------------------------------------------------
  701.   *
  702.   * Remove Namespace Function
  703.   *
  704.   *---------------------------------------------------------------------
  705.   *
  706.   * Delete an entire namespace from the messageSource
  707.   *
  708.   *///------------------------------------------------------------------
  709. removeNamespace: function(namespace){
  710. delete(ms[namespace]);
  711. },
  712.  
  713. /*---------------------------------------------------------------------
  714.   *
  715.   * Remove Message Function
  716.   *
  717.   *---------------------------------------------------------------------
  718.   *
  719.   * Delete a single message from a certain namespace. Will also
  720.   * remove the namespace if it is empty.
  721.   *
  722.   *///------------------------------------------------------------------
  723. removeMessage: function(namespace, msg){
  724.  
  725. delete(ms[namespace][msg]);
  726.  
  727. for(t in ms[namespace]){
  728. return undefined;
  729. }
  730.  
  731. removeNamespace(ms[namespace]);
  732. }
  733. };
  734. })();
  735.  
  736. /*-----------------------------------------------------------------------------
  737.   *
  738.   * Constraints Callback
  739.   *
  740.   *-----------------------------------------------------------------------------
  741.   *
  742.   * Handles the constratint management when a constraint action is triggered.
  743.   *
  744.   *///--------------------------------------------------------------------------
  745. function constraintCallback(event){
  746.  
  747. var cs = $(this).data("constraints");
  748. var cd = $(this).data("constraint-data");
  749.  
  750. var failedConstraints = [];
  751.  
  752. for(c in cs){
  753.  
  754. var pass = cs[c]($(this).val(), cd[c], this);
  755.  
  756. if(!pass){
  757.  
  758. failedConstraints.push({
  759. constraint : c,
  760. message : MessageSource.getMessage(this,c)
  761. });
  762.  
  763. if(event.data.stopOnFirst){ break; }
  764. }
  765. }
  766.  
  767. event.data[(failedConstraints.length > 0)?'errorFn':'successFn'](this, failedConstraints);
  768. }
  769.  
  770. /*-----------------------------------------------------------------------------
  771.   *
  772.   * Constraints Public API
  773.   *
  774.   *-----------------------------------------------------------------------------
  775.   *
  776.   * Extend the core jQuery object to allow access to the public functions
  777.   * for the Constraint functionality
  778.   *
  779.   *///--------------------------------------------------------------------------
  780. $.extend({
  781.  
  782. /*
  783.   * fn.constrain
  784.   * fn.unconstrain
  785.   * constrainForm
  786.   * unconstrainForm
  787.   */
  788.  
  789. cs : {
  790.  
  791. //-- DEFAULT OPTIONS API ----------------------------------------------
  792. defaultOptions : defaultOptions,
  793.  
  794. //-- CONSTRAINT SERVICE API -------------------------------------------
  795. register : ConstraintService.register,
  796. registerAll : ConstraintService.registerAll,
  797. bind : ConstraintService.bind,
  798. unbind : ConstraintService.unbind,
  799. unconstrain : ConstraintService.unconstrain,
  800. unconstrainAll : ConstraintService.unconstrainAll,
  801.  
  802. //-- MESSAGE SOURCE API -----------------------------------------------
  803. addMessages : MessageSource.addMessages,
  804. addMessage : MessageSource.addMessage,
  805. getMessage : MessageSource.getMessage,
  806. deleteMessage : MessageSource.removeMessage,
  807. deleteMessageNamespace : MessageSource.removeNamespace,
  808.  
  809. /*---------------------------------------------------------------------
  810.   *
  811.   * Unistall Constrains plugin
  812.   *
  813.   *---------------------------------------------------------------------
  814.   *
  815.   * Unistall the entire plugin by deregistering all events and data
  816.   * caches in the document but also delete the objects from memory.
  817.   *
  818.   *///------------------------------------------------------------------
  819. uninstall: function(){
  820.  
  821. /* remove constraint data and events */
  822. ConstraintService.unconstrainAll(document);
  823.  
  824. /* delete the object from global object */
  825. delete(constraintCallback);
  826. delete(MessageSource);
  827. delete(ConstraintService);
  828. delete(defaultOptions);
  829. delete($.isEmpty);
  830. delete($.constrainForm);
  831. delete($.unconstrainForm);
  832. delete($.fn.constrain);
  833. delete($.fn.unconstrain);
  834. delete($.constraints);
  835. }
  836. }
  837. });
  838.  
  839. })(jQuery);

Report this snippet


Comments

RSS Icon Subscribe to comments

You need to login to post a comment.