artfully_ose 1.2.0.pre.24 → 1.2.0.pre.26

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +9 -9
  2. data/app/assets/fonts/FontAwesome.otf +0 -0
  3. data/app/assets/fonts/fontawesome-webfont.eot +0 -0
  4. data/app/assets/fonts/fontawesome-webfont.svg +504 -0
  5. data/app/assets/fonts/fontawesome-webfont.ttf +0 -0
  6. data/app/assets/fonts/fontawesome-webfont.woff +0 -0
  7. data/app/assets/javascripts/application.js +5 -0
  8. data/app/assets/javascripts/custom/people.js +68 -5
  9. data/app/assets/javascripts/sales-console.js +153 -0
  10. data/app/assets/javascripts/store/jquery.validate.additional-methods.js +476 -159
  11. data/app/assets/javascripts/store/jquery.validate.js +449 -406
  12. data/app/assets/stylesheets/application.sass +49 -0
  13. data/app/assets/stylesheets/font-awesome.css.scss +1566 -0
  14. data/app/concerns/cart_finder.rb +5 -0
  15. data/app/controllers/console_sales_controller.rb +182 -0
  16. data/app/controllers/events_controller.rb +1 -1
  17. data/app/controllers/events_pass_types_controller.rb +10 -0
  18. data/app/controllers/memberships_controller.rb +3 -3
  19. data/app/controllers/people_controller.rb +2 -1
  20. data/app/controllers/sales_controller.rb +51 -13
  21. data/app/controllers/shows_controller.rb +2 -2
  22. data/app/controllers/store/orders_controller.rb +0 -9
  23. data/app/helpers/artfully_ose_helper.rb +4 -2
  24. data/app/helpers/sales_helper.rb +29 -0
  25. data/app/models/cart.rb +6 -1
  26. data/app/models/checkout.rb +20 -13
  27. data/app/models/comp.rb +13 -16
  28. data/app/models/console_sale.rb +30 -0
  29. data/app/models/database_views/item_view.rb +3 -0
  30. data/app/models/job/checkout_processor.rb +10 -5
  31. data/app/models/kits/mailchimp_kit.rb +2 -1
  32. data/app/models/kits/passes_kit.rb +1 -1
  33. data/app/models/kits/scannable_tickets_kit.rb +3 -4
  34. data/app/models/membership.rb +18 -3
  35. data/app/models/membership_change.rb +1 -1
  36. data/app/models/membership_type.rb +2 -3
  37. data/app/models/order.rb +20 -17
  38. data/app/models/order_handler.rb +21 -0
  39. data/app/models/orders/comp_order.rb +1 -1
  40. data/app/models/parsed_row.rb +45 -2
  41. data/app/models/pass.rb +13 -0
  42. data/app/models/pass_type.rb +16 -0
  43. data/app/models/payment.rb +17 -0
  44. data/app/models/payments/cash_payment.rb +3 -1
  45. data/app/models/payments/check_payment.rb +33 -0
  46. data/app/models/payments/comp_payment.rb +3 -1
  47. data/app/models/payments/credit_card_payment.rb +8 -18
  48. data/app/models/person.rb +27 -3
  49. data/app/models/sale.rb +13 -10
  50. data/app/models/ticket.rb +1 -1
  51. data/app/views/console_sales/_aloha.html.haml +26 -0
  52. data/app/views/console_sales/_cart.html.haml +60 -0
  53. data/app/views/console_sales/_payment.html.haml +111 -0
  54. data/app/views/console_sales/_shows.html.haml +24 -0
  55. data/app/views/console_sales/new.html.haml +143 -0
  56. data/app/views/events/_day_date_show.html.haml +2 -2
  57. data/app/views/events/_ticket_type_fields.html.haml +1 -1
  58. data/app/views/events_pass_types/_form.html.haml +1 -1
  59. data/app/views/events_pass_types/index.html.haml +2 -1
  60. data/app/views/exchanges/new.html.haml +1 -1
  61. data/app/views/imports/people/_new.html.haml +12 -0
  62. data/app/views/kits/_list.html.haml +2 -1
  63. data/app/views/layouts/_menu.html.haml +0 -3
  64. data/app/views/membership_comps/create.html.haml +3 -1
  65. data/app/views/membership_types/_form.html.haml +0 -1
  66. data/app/views/orders/_item_table.haml +5 -3
  67. data/app/views/passes/index.html.haml +2 -2
  68. data/app/views/people/_edit_modal.html.haml +7 -0
  69. data/app/views/people/_work_with_menu.html.haml +4 -1
  70. data/app/views/people/show.html.haml +13 -4
  71. data/app/views/refunds/new.html.haml +1 -1
  72. data/app/views/sales/_boxoffice.html.haml +141 -0
  73. data/app/views/sales/_doorlist.html.haml +79 -0
  74. data/app/views/sales/new.html.haml +33 -125
  75. data/app/views/searches/show.html.haml +1 -1
  76. data/app/views/segments/show.html.haml +1 -1
  77. data/app/views/shows/_ticket_table.html.haml +1 -1
  78. data/app/views/shows/_work_with.html.haml +1 -1
  79. data/app/views/shows/index.html.haml +5 -6
  80. data/app/views/shows/show.html.haml +2 -2
  81. data/config/initializers/devise.rb +1 -1
  82. data/config/initializers/paperclip.rb +16 -0
  83. data/config/routes.rb +10 -1
  84. data/db/migrate/20140507184646_add_bday_attributes_to_person.rb +7 -0
  85. data/db/migrate/20140507201048_add_check_number_to_orders.rb +5 -0
  86. data/db/migrate/20140619194127_add_do_not_call_to_people.artfully_ose_engine.rb +5 -0
  87. data/db/migrate/20140623160543_add_index_to_items.rb +7 -0
  88. data/lib/artfully_ose/engine.rb +5 -4
  89. data/lib/artfully_ose/version.rb +1 -1
  90. data/spec/factories/person_factories.rb +3 -0
  91. metadata +43 -20
@@ -270,6 +270,11 @@ $(document).ready(function() {
270
270
  'regionField' : '#household_address_attributes_state'
271
271
  });
272
272
 
273
+ $(document).locationSelector({
274
+ 'countryField' : '#customer_address_country',
275
+ 'regionField' : '#customer_address_state'
276
+ });
277
+
273
278
 
274
279
  $("form .description").siblings("input").focusin(function(){
275
280
  $("form .description").addClass("active");
@@ -2,11 +2,15 @@ String.prototype.startsWith = function(str)
2
2
  {return (this.match("^"+str)==str)}
3
3
 
4
4
  $(document).ready(function() {
5
- $("#email-subscription input[type=checkbox]").on("click", function(event) {
6
- $("#email-subscription input[type=submit]").removeClass("hidden");
5
+ $("#communication-preference input[type=checkbox]").on("click", function(event) {
6
+ $("#communication-preference input[type=submit]").removeClass("hidden");
7
7
  });
8
-
9
- $("#person_do_not_email").on("click", function(event) {
8
+
9
+ $("#subscription-listing input[type=checkbox]").on("click", function(event) {
10
+ $("#subscription-listing input[type=submit]").removeClass("hidden");
11
+ });
12
+
13
+ $("#person_do_not_call").on("click", function(event) {
10
14
  $lists = $(".mail-chimp-list");
11
15
  if ($(this).attr("checked") != "checked") {
12
16
  $lists.attr("disabled", false);
@@ -156,5 +160,64 @@ $(document).ready(function() {
156
160
  $("#create-mailing-address, #update-mailing-address").show();
157
161
  return false;
158
162
  });
159
-
163
+
164
+ $('#edit_link').click(function(){
165
+ dayDropDownValue.call(this);
166
+ yearDropDownValue.call(this);
167
+ dayValueForSelect.call(this);
168
+ yearValueForSelect.call(this);
169
+ });
170
+
171
+ $('#birth_month').change(function(){
172
+ dayDropDownValue.call(this);
173
+ });
160
174
  });
175
+
176
+ function yearDropDownValue(){
177
+ var year_now = getYear();
178
+ var yearsAsString = "";
179
+
180
+ for(var i = 1920; i <= year_now; i++) {
181
+ yearsAsString += "<option value='" + i + "'>" + i + "</option>";
182
+ }
183
+
184
+ $('#birth_year').html("<option value=''></option>");
185
+ $('#birth_year').append(yearsAsString);
186
+ }
187
+
188
+ function dayDropDownValue(){
189
+ var month = $('#birth_month').val();
190
+ var year = $('#birth_year').val();
191
+ var num_days = daysInMonth(month, 2012);
192
+ var days_range = range(1,num_days + 1);
193
+ var daysAsString = "";
194
+
195
+ for(var i = 1; i < days_range.length; i++) {
196
+ daysAsString += "<option value='" + days_range[i] + "'>" + days_range[i] + "</option>";
197
+ }
198
+
199
+ $('#birth_day').html("<option value=''></option>");
200
+ $('#birth_day').append(daysAsString);
201
+ }
202
+
203
+ function yearValueForSelect(){
204
+ var birth_year = $('div.year').data('person-birth_year');
205
+ $('#birth_year').val(birth_year);
206
+ }
207
+
208
+ function dayValueForSelect(){
209
+ var birth_day = $('div.day').data('person-birth_day');
210
+ $('#birth_day').val(birth_day);
211
+ }
212
+
213
+ function daysInMonth(month,year) {
214
+ return new Date(year, month, 0).getDate();
215
+ }
216
+
217
+ function getYear(){
218
+ return new Date().getFullYear();
219
+ }
220
+
221
+ function range(start,num){
222
+ return Array.apply(start, Array(num)).map(function (_, i) {return i;});
223
+ }
@@ -0,0 +1,153 @@
1
+ //= require store/jquery.validate
2
+ //= require_self
3
+
4
+ $("document").ready(function() {
5
+
6
+ $('#event_selector').change(function () {
7
+ event_id = $('#event_selector').val()
8
+ person_id = $('#event_selector').attr('data-person-id')
9
+
10
+ person_query_string = ""
11
+ if (person_id != undefined) {
12
+ person_query_string = "?person_id=" + person_id
13
+ }
14
+
15
+ $('#show-select-container').show()
16
+ $('#show-select-controls').addClass("loading")
17
+ $('#show_selector').prop("disabled", true)
18
+ $('#ticket-list').html("&nbsp;");
19
+ jQuery.getJSON("/console_sales/events/" + event_id + person_query_string, function(data){
20
+ })
21
+ .done(function(data) {
22
+ $('#show_selector')
23
+ .find('option')
24
+ .remove()
25
+
26
+ $('#show-select-controls').removeClass("loading")
27
+ $('#show-select-container').show()
28
+
29
+ $('#show_selector').append($("<option></option>"))
30
+
31
+ $.each(data, function(index, el) {
32
+ $('#show_selector')
33
+ .append($("<option></option>")
34
+ .attr("value",el.id)
35
+ .text(el.show_time));
36
+ })
37
+
38
+ $('#show_selector').prop("disabled", false)
39
+ })
40
+ .fail(function() {
41
+ //TODO
42
+ })
43
+ })
44
+
45
+ $('#show-select-container').change(function () {
46
+ show_id = $('#show_selector').val()
47
+ person_id = $('#show_selector').attr('data-person-id')
48
+
49
+ person_query_string = ""
50
+ if (person_id != undefined) {
51
+ person_query_string = "?person_id=" + person_id
52
+ }
53
+
54
+ $.ajax({
55
+ url: "/console_sales/shows/" + show_id + person_query_string,
56
+ beforeSend: function ( xhr ) {
57
+ $('#ticket-list').html("&nbsp;");
58
+ $('#ticket-list').addClass("loading")
59
+ }
60
+ }).done(function ( data ) {
61
+ $('#ticket-list').removeClass("loading")
62
+ $('#ticket-list').html(data);
63
+ }).fail(function ( data ) {
64
+ $('#ticket-list').removeClass("loading")
65
+ });
66
+ })
67
+
68
+ $("body").on("click", "a.btn", function() {
69
+ $('label span.required').hide();
70
+ $('.payment-fields').hide();
71
+ $('a.btn').removeClass('active');
72
+
73
+ $(this).addClass('active');
74
+ var payment = $(this).attr('data-payment-select');
75
+ $('#payment_method').val(payment).trigger('change'); // trigger change so form validness can be checked
76
+
77
+ if(payment == 'credit'){
78
+ $('#credit-fields').show();
79
+ $('#credit_card_number').focus();
80
+ $('label span.email-required').show();
81
+ $('label span.name-required').show();
82
+ $('label span.contact-required').show();
83
+ } else if(payment == 'comp') {
84
+ $('label span.name-required').show();
85
+ } else if(payment == 'check') {
86
+ $('#check-fields').show();
87
+ }
88
+ });
89
+
90
+ $('#sales-console-payment-form').validate({
91
+ highlight: function(element, errorClass) {
92
+ $(element).closest('.control-group').addClass(errorClass);
93
+ },
94
+ unhighlight: function(element, errorClass) {
95
+ $(element).closest('.control-group').removeClass(errorClass);
96
+ },
97
+ ignore: ".ignore-validation",
98
+ messages: {
99
+ total: null,
100
+ payment_method: 'Please select a payment method.',
101
+ },
102
+ rules: {
103
+ 'total': {
104
+ required: true
105
+ },
106
+ 'payment_method': {
107
+ required: true
108
+ },
109
+ 'customer[first_name]': {
110
+ required: function(element) {
111
+ return (
112
+ $('#payment_method').val() === 'credit' ||
113
+ $('#payment_method').val() === 'comp'
114
+ )
115
+ }
116
+ },
117
+ 'customer[last_name]': {
118
+ required: function(element) {
119
+ return (
120
+ $('#payment_method').val() === 'credit' ||
121
+ $('#payment_method').val() === 'comp'
122
+ )
123
+ }
124
+ },
125
+ 'customer[email]': {
126
+ email: true,
127
+ required: function(element) {
128
+ return (
129
+ $('#payment_method').val() === 'credit' &&
130
+ !$.trim($('#person_phone').val()).length // empty?
131
+ )
132
+ }
133
+ },
134
+ 'customer[phones_attributes][][number]': {
135
+ required: function(element) {
136
+ return (
137
+ $('#payment_method').val() === 'credit' &&
138
+ !$.trim($('#person_email').val()).length // empty?
139
+ )
140
+ }
141
+ },
142
+ 'credit_card[number]': {
143
+ creditcard: true,
144
+ required: function(element) {
145
+ return (
146
+ $('#payment_method').val() === 'credit'
147
+ )
148
+ }
149
+ },
150
+ }
151
+ });
152
+
153
+ })
@@ -1,14 +1,12 @@
1
- /**
2
- * jQuery Validation Plugin 1.9.0
1
+ /*!
2
+ * jQuery Validation Plugin 1.11.1
3
3
  *
4
4
  * http://bassistance.de/jquery-plugins/jquery-plugin-validation/
5
5
  * http://docs.jquery.com/Plugins/Validation
6
6
  *
7
- * Copyright (c) 2006 - 2011 Jörn Zaefferer
8
- *
9
- * Dual licensed under the MIT and GPL licenses:
7
+ * Copyright 2013 Jörn Zaefferer
8
+ * Released under the MIT license:
10
9
  * http://www.opensource.org/licenses/mit-license.php
11
- * http://www.gnu.org/licenses/gpl.html
12
10
  */
13
11
 
14
12
  (function() {
@@ -16,30 +14,32 @@
16
14
  function stripHtml(value) {
17
15
  // remove html tags and space chars
18
16
  return value.replace(/<.[^<>]*?>/g, ' ').replace(/&nbsp;|&#160;/gi, ' ')
19
- // remove numbers and punctuation
20
- .replace(/[0-9.(),;:!?%#$'"_+=\/-]*/g,'');
17
+ // remove punctuation
18
+ .replace(/[.(),;:!?%#$'"_+=\/\-]*/g,'');
21
19
  }
22
20
  jQuery.validator.addMethod("maxWords", function(value, element, params) {
23
- return this.optional(element) || stripHtml(value).match(/\b\w+\b/g).length < params;
21
+ return this.optional(element) || stripHtml(value).match(/\b\w+\b/g).length <= params;
24
22
  }, jQuery.validator.format("Please enter {0} words or less."));
25
23
 
26
24
  jQuery.validator.addMethod("minWords", function(value, element, params) {
27
- return this.optional(element) || stripHtml(value).match(/\b\w+\b/g).length >= params;
25
+ return this.optional(element) || stripHtml(value).match(/\b\w+\b/g).length >= params;
28
26
  }, jQuery.validator.format("Please enter at least {0} words."));
29
27
 
30
28
  jQuery.validator.addMethod("rangeWords", function(value, element, params) {
31
- return this.optional(element) || stripHtml(value).match(/\b\w+\b/g).length >= params[0] && value.match(/bw+b/g).length < params[1];
29
+ var valueStripped = stripHtml(value);
30
+ var regex = /\b\w+\b/g;
31
+ return this.optional(element) || valueStripped.match(regex).length >= params[0] && valueStripped.match(regex).length <= params[1];
32
32
  }, jQuery.validator.format("Please enter between {0} and {1} words."));
33
33
 
34
- })();
34
+ }());
35
35
 
36
36
  jQuery.validator.addMethod("letterswithbasicpunc", function(value, element) {
37
- return this.optional(element) || /^[a-z-.,()'\"\s]+$/i.test(value);
37
+ return this.optional(element) || /^[a-z\-.,()'"\s]+$/i.test(value);
38
38
  }, "Letters or punctuation only please");
39
39
 
40
40
  jQuery.validator.addMethod("alphanumeric", function(value, element) {
41
41
  return this.optional(element) || /^\w+$/i.test(value);
42
- }, "Letters, numbers, spaces or underscores only please");
42
+ }, "Letters, numbers, and underscores only please");
43
43
 
44
44
  jQuery.validator.addMethod("lettersonly", function(value, element) {
45
45
  return this.optional(element) || /^[a-z]+$/i.test(value);
@@ -50,118 +50,296 @@ jQuery.validator.addMethod("nowhitespace", function(value, element) {
50
50
  }, "No white space please");
51
51
 
52
52
  jQuery.validator.addMethod("ziprange", function(value, element) {
53
- return this.optional(element) || /^90[2-5]\d\{2}-\d{4}$/.test(value);
53
+ return this.optional(element) || /^90[2-5]\d\{2\}-\d{4}$/.test(value);
54
54
  }, "Your ZIP-code must be in the range 902xx-xxxx to 905-xx-xxxx");
55
55
 
56
+ jQuery.validator.addMethod("zipcodeUS", function(value, element) {
57
+ return this.optional(element) || /\d{5}-\d{4}$|^\d{5}$/.test(value);
58
+ }, "The specified US ZIP Code is invalid");
59
+
56
60
  jQuery.validator.addMethod("integer", function(value, element) {
57
61
  return this.optional(element) || /^-?\d+$/.test(value);
58
62
  }, "A positive or negative non-decimal number please");
59
63
 
60
64
  /**
61
- * Return true, if the value is a valid vehicle identification number (VIN).
62
- *
63
- * Works with all kind of text inputs.
64
- *
65
- * @example <input type="text" size="20" name="VehicleID" class="{required:true,vinUS:true}" />
66
- * @desc Declares a required input element whose value must be a valid vehicle identification number.
67
- *
68
- * @name jQuery.validator.methods.vinUS
69
- * @type Boolean
70
- * @cat Plugins/Validate/Methods
71
- */
72
- jQuery.validator.addMethod(
73
- "vinUS",
74
- function(v){
75
- if (v.length != 17)
76
- return false;
77
- var i, n, d, f, cd, cdv;
78
- var LL = ["A","B","C","D","E","F","G","H","J","K","L","M","N","P","R","S","T","U","V","W","X","Y","Z"];
79
- var VL = [1,2,3,4,5,6,7,8,1,2,3,4,5,7,9,2,3,4,5,6,7,8,9];
80
- var FL = [8,7,6,5,4,3,2,10,0,9,8,7,6,5,4,3,2];
81
- var rs = 0;
82
- for(i = 0; i < 17; i++){
83
- f = FL[i];
84
- d = v.slice(i,i+1);
85
- if(i == 8){
86
- cdv = d;
87
- }
88
- if(!isNaN(d)){
89
- d *= f;
90
- }
91
- else{
92
- for(n = 0; n < LL.length; n++){
93
- if(d.toUpperCase() === LL[n]){
94
- d = VL[n];
95
- d *= f;
96
- if(isNaN(cdv) && n == 8){
97
- cdv = LL[n];
98
- }
99
- break;
100
- }
101
- }
102
- }
103
- rs += d;
104
- }
105
- cd = rs % 11;
106
- if(cd == 10){cd = "X";}
107
- if(cd == cdv){return true;}
65
+ * Return true, if the value is a valid vehicle identification number (VIN).
66
+ *
67
+ * Works with all kind of text inputs.
68
+ *
69
+ * @example <input type="text" size="20" name="VehicleID" class="{required:true,vinUS:true}" />
70
+ * @desc Declares a required input element whose value must be a valid vehicle identification number.
71
+ *
72
+ * @name jQuery.validator.methods.vinUS
73
+ * @type Boolean
74
+ * @cat Plugins/Validate/Methods
75
+ */
76
+ jQuery.validator.addMethod("vinUS", function(v) {
77
+ if (v.length !== 17) {
108
78
  return false;
109
- },
110
- "The specified vehicle identification number (VIN) is invalid."
111
- );
79
+ }
80
+ var i, n, d, f, cd, cdv;
81
+ var LL = ["A","B","C","D","E","F","G","H","J","K","L","M","N","P","R","S","T","U","V","W","X","Y","Z"];
82
+ var VL = [1,2,3,4,5,6,7,8,1,2,3,4,5,7,9,2,3,4,5,6,7,8,9];
83
+ var FL = [8,7,6,5,4,3,2,10,0,9,8,7,6,5,4,3,2];
84
+ var rs = 0;
85
+ for(i = 0; i < 17; i++){
86
+ f = FL[i];
87
+ d = v.slice(i,i+1);
88
+ if (i === 8) {
89
+ cdv = d;
90
+ }
91
+ if (!isNaN(d)) {
92
+ d *= f;
93
+ } else {
94
+ for (n = 0; n < LL.length; n++) {
95
+ if (d.toUpperCase() === LL[n]) {
96
+ d = VL[n];
97
+ d *= f;
98
+ if (isNaN(cdv) && n === 8) {
99
+ cdv = LL[n];
100
+ }
101
+ break;
102
+ }
103
+ }
104
+ }
105
+ rs += d;
106
+ }
107
+ cd = rs % 11;
108
+ if (cd === 10) {
109
+ cd = "X";
110
+ }
111
+ if (cd === cdv) {
112
+ return true;
113
+ }
114
+ return false;
115
+ }, "The specified vehicle identification number (VIN) is invalid.");
112
116
 
113
117
  /**
114
- * Return true, if the value is a valid date, also making this formal check dd/mm/yyyy.
115
- *
116
- * @example jQuery.validator.methods.date("01/01/1900")
117
- * @result true
118
- *
119
- * @example jQuery.validator.methods.date("01/13/1990")
120
- * @result false
121
- *
122
- * @example jQuery.validator.methods.date("01.01.1900")
123
- * @result false
124
- *
125
- * @example <input name="pippo" class="{dateITA:true}" />
126
- * @desc Declares an optional input element whose value must be a valid date.
127
- *
128
- * @name jQuery.validator.methods.dateITA
129
- * @type Boolean
130
- * @cat Plugins/Validate/Methods
131
- */
132
- jQuery.validator.addMethod(
133
- "dateITA",
134
- function(value, element) {
135
- var check = false;
136
- var re = /^\d{1,2}\/\d{1,2}\/\d{4}$/;
137
- if( re.test(value)){
138
- var adata = value.split('/');
139
- var gg = parseInt(adata[0],10);
140
- var mm = parseInt(adata[1],10);
141
- var aaaa = parseInt(adata[2],10);
142
- var xdata = new Date(aaaa,mm-1,gg);
143
- if ( ( xdata.getFullYear() == aaaa ) && ( xdata.getMonth () == mm - 1 ) && ( xdata.getDate() == gg ) )
144
- check = true;
145
- else
146
- check = false;
147
- } else
118
+ * Return true, if the value is a valid date, also making this formal check dd/mm/yyyy.
119
+ *
120
+ * @example jQuery.validator.methods.date("01/01/1900")
121
+ * @result true
122
+ *
123
+ * @example jQuery.validator.methods.date("01/13/1990")
124
+ * @result false
125
+ *
126
+ * @example jQuery.validator.methods.date("01.01.1900")
127
+ * @result false
128
+ *
129
+ * @example <input name="pippo" class="{dateITA:true}" />
130
+ * @desc Declares an optional input element whose value must be a valid date.
131
+ *
132
+ * @name jQuery.validator.methods.dateITA
133
+ * @type Boolean
134
+ * @cat Plugins/Validate/Methods
135
+ */
136
+ jQuery.validator.addMethod("dateITA", function(value, element) {
137
+ var check = false;
138
+ var re = /^\d{1,2}\/\d{1,2}\/\d{4}$/;
139
+ if( re.test(value)) {
140
+ var adata = value.split('/');
141
+ var gg = parseInt(adata[0],10);
142
+ var mm = parseInt(adata[1],10);
143
+ var aaaa = parseInt(adata[2],10);
144
+ var xdata = new Date(aaaa,mm-1,gg);
145
+ if ( ( xdata.getFullYear() === aaaa ) && ( xdata.getMonth() === mm - 1 ) && ( xdata.getDate() === gg ) ){
146
+ check = true;
147
+ } else {
148
148
  check = false;
149
- return this.optional(element) || check;
150
- },
151
- "Please enter a correct date"
152
- );
149
+ }
150
+ } else {
151
+ check = false;
152
+ }
153
+ return this.optional(element) || check;
154
+ }, "Please enter a correct date");
155
+
156
+ /**
157
+ * IBAN is the international bank account number.
158
+ * It has a country - specific format, that is checked here too
159
+ */
160
+ jQuery.validator.addMethod("iban", function(value, element) {
161
+ // some quick simple tests to prevent needless work
162
+ if (this.optional(element)) {
163
+ return true;
164
+ }
165
+ if (!(/^([a-zA-Z0-9]{4} ){2,8}[a-zA-Z0-9]{1,4}|[a-zA-Z0-9]{12,34}$/.test(value))) {
166
+ return false;
167
+ }
168
+
169
+ // check the country code and find the country specific format
170
+ var iban = value.replace(/ /g,'').toUpperCase(); // remove spaces and to upper case
171
+ var countrycode = iban.substring(0,2);
172
+ var bbancountrypatterns = {
173
+ 'AL': "\\d{8}[\\dA-Z]{16}",
174
+ 'AD': "\\d{8}[\\dA-Z]{12}",
175
+ 'AT': "\\d{16}",
176
+ 'AZ': "[\\dA-Z]{4}\\d{20}",
177
+ 'BE': "\\d{12}",
178
+ 'BH': "[A-Z]{4}[\\dA-Z]{14}",
179
+ 'BA': "\\d{16}",
180
+ 'BR': "\\d{23}[A-Z][\\dA-Z]",
181
+ 'BG': "[A-Z]{4}\\d{6}[\\dA-Z]{8}",
182
+ 'CR': "\\d{17}",
183
+ 'HR': "\\d{17}",
184
+ 'CY': "\\d{8}[\\dA-Z]{16}",
185
+ 'CZ': "\\d{20}",
186
+ 'DK': "\\d{14}",
187
+ 'DO': "[A-Z]{4}\\d{20}",
188
+ 'EE': "\\d{16}",
189
+ 'FO': "\\d{14}",
190
+ 'FI': "\\d{14}",
191
+ 'FR': "\\d{10}[\\dA-Z]{11}\\d{2}",
192
+ 'GE': "[\\dA-Z]{2}\\d{16}",
193
+ 'DE': "\\d{18}",
194
+ 'GI': "[A-Z]{4}[\\dA-Z]{15}",
195
+ 'GR': "\\d{7}[\\dA-Z]{16}",
196
+ 'GL': "\\d{14}",
197
+ 'GT': "[\\dA-Z]{4}[\\dA-Z]{20}",
198
+ 'HU': "\\d{24}",
199
+ 'IS': "\\d{22}",
200
+ 'IE': "[\\dA-Z]{4}\\d{14}",
201
+ 'IL': "\\d{19}",
202
+ 'IT': "[A-Z]\\d{10}[\\dA-Z]{12}",
203
+ 'KZ': "\\d{3}[\\dA-Z]{13}",
204
+ 'KW': "[A-Z]{4}[\\dA-Z]{22}",
205
+ 'LV': "[A-Z]{4}[\\dA-Z]{13}",
206
+ 'LB': "\\d{4}[\\dA-Z]{20}",
207
+ 'LI': "\\d{5}[\\dA-Z]{12}",
208
+ 'LT': "\\d{16}",
209
+ 'LU': "\\d{3}[\\dA-Z]{13}",
210
+ 'MK': "\\d{3}[\\dA-Z]{10}\\d{2}",
211
+ 'MT': "[A-Z]{4}\\d{5}[\\dA-Z]{18}",
212
+ 'MR': "\\d{23}",
213
+ 'MU': "[A-Z]{4}\\d{19}[A-Z]{3}",
214
+ 'MC': "\\d{10}[\\dA-Z]{11}\\d{2}",
215
+ 'MD': "[\\dA-Z]{2}\\d{18}",
216
+ 'ME': "\\d{18}",
217
+ 'NL': "[A-Z]{4}\\d{10}",
218
+ 'NO': "\\d{11}",
219
+ 'PK': "[\\dA-Z]{4}\\d{16}",
220
+ 'PS': "[\\dA-Z]{4}\\d{21}",
221
+ 'PL': "\\d{24}",
222
+ 'PT': "\\d{21}",
223
+ 'RO': "[A-Z]{4}[\\dA-Z]{16}",
224
+ 'SM': "[A-Z]\\d{10}[\\dA-Z]{12}",
225
+ 'SA': "\\d{2}[\\dA-Z]{18}",
226
+ 'RS': "\\d{18}",
227
+ 'SK': "\\d{20}",
228
+ 'SI': "\\d{15}",
229
+ 'ES': "\\d{20}",
230
+ 'SE': "\\d{20}",
231
+ 'CH': "\\d{5}[\\dA-Z]{12}",
232
+ 'TN': "\\d{20}",
233
+ 'TR': "\\d{5}[\\dA-Z]{17}",
234
+ 'AE': "\\d{3}\\d{16}",
235
+ 'GB': "[A-Z]{4}\\d{14}",
236
+ 'VG': "[\\dA-Z]{4}\\d{16}"
237
+ };
238
+ var bbanpattern = bbancountrypatterns[countrycode];
239
+ // As new countries will start using IBAN in the
240
+ // future, we only check if the countrycode is known.
241
+ // This prevents false negatives, while almost all
242
+ // false positives introduced by this, will be caught
243
+ // by the checksum validation below anyway.
244
+ // Strict checking should return FALSE for unknown
245
+ // countries.
246
+ if (typeof bbanpattern !== 'undefined') {
247
+ var ibanregexp = new RegExp("^[A-Z]{2}\\d{2}" + bbanpattern + "$", "");
248
+ if (!(ibanregexp.test(iban))) {
249
+ return false; // invalid country specific format
250
+ }
251
+ }
252
+
253
+ // now check the checksum, first convert to digits
254
+ var ibancheck = iban.substring(4,iban.length) + iban.substring(0,4);
255
+ var ibancheckdigits = "";
256
+ var leadingZeroes = true;
257
+ var charAt;
258
+ for (var i =0; i<ibancheck.length; i++) {
259
+ charAt = ibancheck.charAt(i);
260
+ if (charAt !== "0") {
261
+ leadingZeroes = false;
262
+ }
263
+ if (!leadingZeroes) {
264
+ ibancheckdigits += "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".indexOf(charAt);
265
+ }
266
+ }
267
+
268
+ // calculate the result of: ibancheckdigits % 97
269
+ var cRest = '';
270
+ var cOperator = '';
271
+ for (var p=0; p<ibancheckdigits.length; p++) {
272
+ var cChar = ibancheckdigits.charAt(p);
273
+ cOperator = '' + cRest + '' + cChar;
274
+ cRest = cOperator % 97;
275
+ }
276
+ return cRest === 1;
277
+ }, "Please specify a valid IBAN");
153
278
 
154
279
  jQuery.validator.addMethod("dateNL", function(value, element) {
155
- return this.optional(element) || /^\d\d?[\.\/-]\d\d?[\.\/-]\d\d\d?\d?$/.test(value);
156
- }, "Vul hier een geldige datum in."
157
- );
280
+ return this.optional(element) || /^(0?[1-9]|[12]\d|3[01])[\.\/\-](0?[1-9]|1[012])[\.\/\-]([12]\d)?(\d\d)$/.test(value);
281
+ }, "Please enter a correct date");
282
+
283
+ /**
284
+ * Dutch phone numbers have 10 digits (or 11 and start with +31).
285
+ */
286
+ jQuery.validator.addMethod("phoneNL", function(value, element) {
287
+ return this.optional(element) || /^((\+|00(\s|\s?\-\s?)?)31(\s|\s?\-\s?)?(\(0\)[\-\s]?)?|0)[1-9]((\s|\s?\-\s?)?[0-9]){8}$/.test(value);
288
+ }, "Please specify a valid phone number.");
289
+
290
+ jQuery.validator.addMethod("mobileNL", function(value, element) {
291
+ return this.optional(element) || /^((\+|00(\s|\s?\-\s?)?)31(\s|\s?\-\s?)?(\(0\)[\-\s]?)?|0)6((\s|\s?\-\s?)?[0-9]){8}$/.test(value);
292
+ }, "Please specify a valid mobile number");
293
+
294
+ jQuery.validator.addMethod("postalcodeNL", function(value, element) {
295
+ return this.optional(element) || /^[1-9][0-9]{3}\s?[a-zA-Z]{2}$/.test(value);
296
+ }, "Please specify a valid postal code");
297
+
298
+ /*
299
+ * Dutch bank account numbers (not 'giro' numbers) have 9 digits
300
+ * and pass the '11 check'.
301
+ * We accept the notation with spaces, as that is common.
302
+ * acceptable: 123456789 or 12 34 56 789
303
+ */
304
+ jQuery.validator.addMethod("bankaccountNL", function(value, element) {
305
+ if (this.optional(element)) {
306
+ return true;
307
+ }
308
+ if (!(/^[0-9]{9}|([0-9]{2} ){3}[0-9]{3}$/.test(value))) {
309
+ return false;
310
+ }
311
+ // now '11 check'
312
+ var account = value.replace(/ /g,''); // remove spaces
313
+ var sum = 0;
314
+ var len = account.length;
315
+ for (var pos=0; pos<len; pos++) {
316
+ var factor = len - pos;
317
+ var digit = account.substring(pos, pos+1);
318
+ sum = sum + factor * digit;
319
+ }
320
+ return sum % 11 === 0;
321
+ }, "Please specify a valid bank account number");
322
+
323
+ /**
324
+ * Dutch giro account numbers (not bank numbers) have max 7 digits
325
+ */
326
+ jQuery.validator.addMethod("giroaccountNL", function(value, element) {
327
+ return this.optional(element) || /^[0-9]{1,7}$/.test(value);
328
+ }, "Please specify a valid giro account number");
329
+
330
+ jQuery.validator.addMethod("bankorgiroaccountNL", function(value, element) {
331
+ return this.optional(element) ||
332
+ ($.validator.methods["bankaccountNL"].call(this, value, element)) ||
333
+ ($.validator.methods["giroaccountNL"].call(this, value, element));
334
+ }, "Please specify a valid bank or giro account number");
335
+
158
336
 
159
337
  jQuery.validator.addMethod("time", function(value, element) {
160
- return this.optional(element) || /^([01]\d|2[0-3])(:[0-5]\d){0,2}$/.test(value);
338
+ return this.optional(element) || /^([01]\d|2[0-3])(:[0-5]\d){1,2}$/.test(value);
161
339
  }, "Please enter a valid time, between 00:00 and 23:59");
162
340
  jQuery.validator.addMethod("time12h", function(value, element) {
163
- return this.optional(element) || /^((0?[1-9]|1[012])(:[0-5]\d){0,2}(\ [AP]M))$/i.test(value);
164
- }, "Please enter a valid time, between 00:00 am and 12:00 pm");
341
+ return this.optional(element) || /^((0?[1-9]|1[012])(:[0-5]\d){1,2}(\ ?[AP]M))$/i.test(value);
342
+ }, "Please enter a valid time in 12-hour am/pm format");
165
343
 
166
344
  /**
167
345
  * matches US phone number format
@@ -170,10 +348,8 @@ jQuery.validator.addMethod("time12h", function(value, element) {
170
348
  * allows '-' or ' ' as a separator and allows parens around area code
171
349
  * some people may want to put a '1' in front of their number
172
350
  *
173
- * 1(212)-999-2345
174
- * or
175
- * 212 999 2344
176
- * or
351
+ * 1(212)-999-2345 or
352
+ * 212 999 2344 or
177
353
  * 212-999-0983
178
354
  *
179
355
  * but not
@@ -182,21 +358,42 @@ jQuery.validator.addMethod("time12h", function(value, element) {
182
358
  * 212 123 4567
183
359
  */
184
360
  jQuery.validator.addMethod("phoneUS", function(phone_number, element) {
185
- phone_number = phone_number.replace(/\s+/g, "");
361
+ phone_number = phone_number.replace(/\s+/g, "");
186
362
  return this.optional(element) || phone_number.length > 9 &&
187
- phone_number.match(/^(1-?)?(\([2-9]\d{2}\)|[2-9]\d{2})-?[2-9]\d{2}-?\d{4}$/);
363
+ phone_number.match(/^(\+?1-?)?(\([2-9]\d{2}\)|[2-9]\d{2})-?[2-9]\d{2}-?\d{4}$/);
188
364
  }, "Please specify a valid phone number");
189
365
 
190
366
  jQuery.validator.addMethod('phoneUK', function(phone_number, element) {
191
- return this.optional(element) || phone_number.length > 9 &&
192
- phone_number.match(/^(\(?(0|\+44)[1-9]{1}\d{1,4}?\)?\s?\d{3,4}\s?\d{3,4})$/);
367
+ phone_number = phone_number.replace(/\(|\)|\s+|-/g,'');
368
+ return this.optional(element) || phone_number.length > 9 &&
369
+ phone_number.match(/^(?:(?:(?:00\s?|\+)44\s?)|(?:\(?0))(?:\d{2}\)?\s?\d{4}\s?\d{4}|\d{3}\)?\s?\d{3}\s?\d{3,4}|\d{4}\)?\s?(?:\d{5}|\d{3}\s?\d{3})|\d{5}\)?\s?\d{4,5})$/);
193
370
  }, 'Please specify a valid phone number');
194
371
 
195
372
  jQuery.validator.addMethod('mobileUK', function(phone_number, element) {
196
- return this.optional(element) || phone_number.length > 9 &&
197
- phone_number.match(/^((0|\+44)7(5|6|7|8|9){1}\d{2}\s?\d{6})$/);
373
+ phone_number = phone_number.replace(/\(|\)|\s+|-/g,'');
374
+ return this.optional(element) || phone_number.length > 9 &&
375
+ phone_number.match(/^(?:(?:(?:00\s?|\+)44\s?|0)7(?:[45789]\d{2}|624)\s?\d{3}\s?\d{3})$/);
198
376
  }, 'Please specify a valid mobile number');
199
377
 
378
+ //Matches UK landline + mobile, accepting only 01-3 for landline or 07 for mobile to exclude many premium numbers
379
+ jQuery.validator.addMethod('phonesUK', function(phone_number, element) {
380
+ phone_number = phone_number.replace(/\(|\)|\s+|-/g,'');
381
+ return this.optional(element) || phone_number.length > 9 &&
382
+ phone_number.match(/^(?:(?:(?:00\s?|\+)44\s?|0)(?:1\d{8,9}|[23]\d{9}|7(?:[45789]\d{8}|624\d{6})))$/);
383
+ }, 'Please specify a valid uk phone number');
384
+ // On the above three UK functions, do the following server side processing:
385
+ // Compare original input with this RegEx pattern:
386
+ // ^\(?(?:(?:00\)?[\s\-]?\(?|\+)(44)\)?[\s\-]?\(?(?:0\)?[\s\-]?\(?)?|0)([1-9]\d{1,4}\)?[\s\d\-]+)$
387
+ // Extract $1 and set $prefix to '+44<space>' if $1 is '44', otherwise set $prefix to '0'
388
+ // Extract $2 and remove hyphens, spaces and parentheses. Phone number is combined $prefix and $2.
389
+ // A number of very detailed GB telephone number RegEx patterns can also be found at:
390
+ // http://www.aa-asterisk.org.uk/index.php/Regular_Expressions_for_Validating_and_Formatting_GB_Telephone_Numbers
391
+
392
+ // Matches UK postcode. Does not match to UK Channel Islands that have their own postcodes (non standard UK)
393
+ jQuery.validator.addMethod('postcodeUK', function(value, element) {
394
+ return this.optional(element) || /^((([A-PR-UWYZ][0-9])|([A-PR-UWYZ][0-9][0-9])|([A-PR-UWYZ][A-HK-Y][0-9])|([A-PR-UWYZ][A-HK-Y][0-9][0-9])|([A-PR-UWYZ][0-9][A-HJKSTUW])|([A-PR-UWYZ][A-HK-Y][0-9][ABEHMNPRVWXY]))\s?([0-9][ABD-HJLNP-UW-Z]{2})|(GIR)\s?(0AA))$/i.test(value);
395
+ }, 'Please specify a valid UK postcode');
396
+
200
397
  // TODO check if value starts with <, otherwise don't try stripping anything
201
398
  jQuery.validator.addMethod("strippedminlength", function(value, element, param) {
202
399
  return jQuery(value).text().length >= param;
@@ -209,63 +406,71 @@ jQuery.validator.addMethod("email2", function(value, element, param) {
209
406
 
210
407
  // same as url, but TLD is optional
211
408
  jQuery.validator.addMethod("url2", function(value, element, param) {
212
- return this.optional(element) || /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)*(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value);
409
+ return this.optional(element) || /^(https?|ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)*(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value);
213
410
  }, jQuery.validator.messages.url);
214
411
 
215
412
  // NOTICE: Modified version of Castle.Components.Validator.CreditCardValidator
216
413
  // Redistributed under the the Apache License 2.0 at http://www.apache.org/licenses/LICENSE-2.0
217
414
  // Valid Types: mastercard, visa, amex, dinersclub, enroute, discover, jcb, unknown, all (overrides all other settings)
218
415
  jQuery.validator.addMethod("creditcardtypes", function(value, element, param) {
219
-
220
- if (/[^0-9-]+/.test(value))
416
+ if (/[^0-9\-]+/.test(value)) {
221
417
  return false;
418
+ }
222
419
 
223
420
  value = value.replace(/\D/g, "");
224
421
 
225
422
  var validTypes = 0x0000;
226
423
 
227
- if (param.mastercard)
424
+ if (param.mastercard) {
228
425
  validTypes |= 0x0001;
229
- if (param.visa)
426
+ }
427
+ if (param.visa) {
230
428
  validTypes |= 0x0002;
231
- if (param.amex)
429
+ }
430
+ if (param.amex) {
232
431
  validTypes |= 0x0004;
233
- if (param.dinersclub)
432
+ }
433
+ if (param.dinersclub) {
234
434
  validTypes |= 0x0008;
235
- if (param.enroute)
435
+ }
436
+ if (param.enroute) {
236
437
  validTypes |= 0x0010;
237
- if (param.discover)
438
+ }
439
+ if (param.discover) {
238
440
  validTypes |= 0x0020;
239
- if (param.jcb)
441
+ }
442
+ if (param.jcb) {
240
443
  validTypes |= 0x0040;
241
- if (param.unknown)
444
+ }
445
+ if (param.unknown) {
242
446
  validTypes |= 0x0080;
243
- if (param.all)
447
+ }
448
+ if (param.all) {
244
449
  validTypes = 0x0001 | 0x0002 | 0x0004 | 0x0008 | 0x0010 | 0x0020 | 0x0040 | 0x0080;
245
-
246
- if (validTypes & 0x0001 && /^(51|52|53|54|55)/.test(value)) { //mastercard
247
- return value.length == 16;
450
+ }
451
+ if (validTypes & 0x0001 && /^(5[12345])/.test(value)) { //mastercard
452
+ return value.length === 16;
248
453
  }
249
454
  if (validTypes & 0x0002 && /^(4)/.test(value)) { //visa
250
- return value.length == 16;
455
+ return value.length === 16;
251
456
  }
252
- if (validTypes & 0x0004 && /^(34|37)/.test(value)) { //amex
253
- return value.length == 15;
457
+ if (validTypes & 0x0004 && /^(3[47])/.test(value)) { //amex
458
+ return value.length === 15;
254
459
  }
255
- if (validTypes & 0x0008 && /^(300|301|302|303|304|305|36|38)/.test(value)) { //dinersclub
256
- return value.length == 14;
460
+ if (validTypes & 0x0008 && /^(3(0[012345]|[68]))/.test(value)) { //dinersclub
461
+ return value.length === 14;
257
462
  }
258
- if (validTypes & 0x0010 && /^(2014|2149)/.test(value)) { //enroute
259
- return value.length == 15;
463
+ if (validTypes & 0x0010 && /^(2(014|149))/.test(value)) { //enroute
464
+ return value.length === 15;
260
465
  }
261
466
  if (validTypes & 0x0020 && /^(6011)/.test(value)) { //discover
262
- return value.length == 16;
467
+ return value.length === 16;
263
468
  }
264
469
  if (validTypes & 0x0040 && /^(3)/.test(value)) { //jcb
265
- return value.length == 16;
470
+ return value.length === 16;
266
471
  }
267
472
  if (validTypes & 0x0040 && /^(2131|1800)/.test(value)) { //jcb
268
- return value.length == 15;
473
+ return value.length === 15;
269
474
  }
270
475
  if (validTypes & 0x0080) { //unknown
271
476
  return true;
@@ -274,27 +479,139 @@ jQuery.validator.addMethod("creditcardtypes", function(value, element, param) {
274
479
  }, "Please enter a valid credit card number.");
275
480
 
276
481
  jQuery.validator.addMethod("ipv4", function(value, element, param) {
277
- return this.optional(element) || /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/i.test(value);
482
+ return this.optional(element) || /^(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)\.(25[0-5]|2[0-4]\d|[01]?\d\d?)$/i.test(value);
278
483
  }, "Please enter a valid IP v4 address.");
279
484
 
280
485
  jQuery.validator.addMethod("ipv6", function(value, element, param) {
281
- return this.optional(element) || /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i.test(value);
486
+ return this.optional(element) || /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/i.test(value);
282
487
  }, "Please enter a valid IP v6 address.");
283
488
 
284
489
  /**
285
- * Return true if the field value matches the given format RegExp
286
- *
287
- * @example jQuery.validator.methods.pattern("AR1004",element,/^AR\d{4}$/)
288
- * @result true
289
- *
290
- * @example jQuery.validator.methods.pattern("BR1004",element,/^AR\d{4}$/)
291
- * @result false
292
- *
293
- * @name jQuery.validator.methods.pattern
294
- * @type Boolean
295
- * @cat Plugins/Validate/Methods
296
- */
490
+ * Return true if the field value matches the given format RegExp
491
+ *
492
+ * @example jQuery.validator.methods.pattern("AR1004",element,/^AR\d{4}$/)
493
+ * @result true
494
+ *
495
+ * @example jQuery.validator.methods.pattern("BR1004",element,/^AR\d{4}$/)
496
+ * @result false
497
+ *
498
+ * @name jQuery.validator.methods.pattern
499
+ * @type Boolean
500
+ * @cat Plugins/Validate/Methods
501
+ */
297
502
  jQuery.validator.addMethod("pattern", function(value, element, param) {
298
- return this.optional(element) || param.test(value);
503
+ if (this.optional(element)) {
504
+ return true;
505
+ }
506
+ if (typeof param === 'string') {
507
+ param = new RegExp('^(?:' + param + ')$');
508
+ }
509
+ return param.test(value);
299
510
  }, "Invalid format.");
300
511
 
512
+
513
+ /*
514
+ * Lets you say "at least X inputs that match selector Y must be filled."
515
+ *
516
+ * The end result is that neither of these inputs:
517
+ *
518
+ * <input class="productinfo" name="partnumber">
519
+ * <input class="productinfo" name="description">
520
+ *
521
+ * ...will validate unless at least one of them is filled.
522
+ *
523
+ * partnumber: {require_from_group: [1,".productinfo"]},
524
+ * description: {require_from_group: [1,".productinfo"]}
525
+ *
526
+ */
527
+ jQuery.validator.addMethod("require_from_group", function(value, element, options) {
528
+ var validator = this;
529
+ var selector = options[1];
530
+ var validOrNot = $(selector, element.form).filter(function() {
531
+ return validator.elementValue(this);
532
+ }).length >= options[0];
533
+
534
+ if(!$(element).data('being_validated')) {
535
+ var fields = $(selector, element.form);
536
+ fields.data('being_validated', true);
537
+ fields.valid();
538
+ fields.data('being_validated', false);
539
+ }
540
+ return validOrNot;
541
+ }, jQuery.format("Please fill at least {0} of these fields."));
542
+
543
+ /*
544
+ * Lets you say "either at least X inputs that match selector Y must be filled,
545
+ * OR they must all be skipped (left blank)."
546
+ *
547
+ * The end result, is that none of these inputs:
548
+ *
549
+ * <input class="productinfo" name="partnumber">
550
+ * <input class="productinfo" name="description">
551
+ * <input class="productinfo" name="color">
552
+ *
553
+ * ...will validate unless either at least two of them are filled,
554
+ * OR none of them are.
555
+ *
556
+ * partnumber: {skip_or_fill_minimum: [2,".productinfo"]},
557
+ * description: {skip_or_fill_minimum: [2,".productinfo"]},
558
+ * color: {skip_or_fill_minimum: [2,".productinfo"]}
559
+ *
560
+ */
561
+ jQuery.validator.addMethod("skip_or_fill_minimum", function(value, element, options) {
562
+ var validator = this,
563
+ numberRequired = options[0],
564
+ selector = options[1];
565
+ var numberFilled = $(selector, element.form).filter(function() {
566
+ return validator.elementValue(this);
567
+ }).length;
568
+ var valid = numberFilled >= numberRequired || numberFilled === 0;
569
+
570
+ if(!$(element).data('being_validated')) {
571
+ var fields = $(selector, element.form);
572
+ fields.data('being_validated', true);
573
+ fields.valid();
574
+ fields.data('being_validated', false);
575
+ }
576
+ return valid;
577
+ }, jQuery.format("Please either skip these fields or fill at least {0} of them."));
578
+
579
+ // Accept a value from a file input based on a required mimetype
580
+ jQuery.validator.addMethod("accept", function(value, element, param) {
581
+ // Split mime on commas in case we have multiple types we can accept
582
+ var typeParam = typeof param === "string" ? param.replace(/\s/g, '').replace(/,/g, '|') : "image/*",
583
+ optionalValue = this.optional(element),
584
+ i, file;
585
+
586
+ // Element is optional
587
+ if (optionalValue) {
588
+ return optionalValue;
589
+ }
590
+
591
+ if ($(element).attr("type") === "file") {
592
+ // If we are using a wildcard, make it regex friendly
593
+ typeParam = typeParam.replace(/\*/g, ".*");
594
+
595
+ // Check if the element has a FileList before checking each file
596
+ if (element.files && element.files.length) {
597
+ for (i = 0; i < element.files.length; i++) {
598
+ file = element.files[i];
599
+
600
+ // Grab the mimetype from the loaded file, verify it matches
601
+ if (!file.type.match(new RegExp( ".?(" + typeParam + ")$", "i"))) {
602
+ return false;
603
+ }
604
+ }
605
+ }
606
+ }
607
+
608
+ // Either return true because we've validated each file, or because the
609
+ // browser does not support element.files and the FileList feature
610
+ return true;
611
+ }, jQuery.format("Please enter a value with a valid mimetype."));
612
+
613
+ // Older "accept" file extension method. Old docs: http://docs.jquery.com/Plugins/Validation/Methods/accept
614
+ jQuery.validator.addMethod("extension", function(value, element, param) {
615
+ param = typeof param === "string" ? param.replace(/,/g, '|') : "png|jpe?g|gif";
616
+ return this.optional(element) || value.match(new RegExp(".(" + param + ")$", "i"));
617
+ }, jQuery.format("Please enter a value with a valid extension."));