jinda 0.5.6 → 0.6.1
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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/generators/jinda/install_generator.rb +6 -3
- data/lib/generators/jinda/templates/app/controllers/jinda_org/application_controller.rb +0 -1
- data/lib/generators/jinda/templates/app/controllers/jinda_org/articles_controller.rb +60 -35
- data/lib/generators/jinda/templates/app/controllers/jinda_org/comments_controller.rb +12 -10
- data/lib/generators/jinda/templates/app/jinda/index.mm +16 -6
- data/lib/generators/jinda/templates/app/jinda/template/index.mm +366 -0
- data/lib/generators/jinda/templates/app/views/articles/edit.haml +7 -7
- data/lib/generators/jinda/templates/app/views/articles/index.haml +2 -2
- data/lib/generators/jinda/templates/app/views/articles/my.haml +3 -3
- data/lib/generators/jinda/templates/app/views/articles/show.html.haml +4 -3
- data/lib/generators/jinda/templates/app/views/jinda/_menu.haml +2 -1
- data/lib/generators/jinda/templates/app/views/jinda/index.html.haml +51 -41
- data/lib/generators/jinda/templates/app/views/layouts/_head.html.erb +2 -2
- data/lib/jinda/helpers.rb +2 -1
- data/lib/jinda/version.rb +1 -1
- data/lib/jquery.validate.js +1293 -0
- metadata +16 -14
@@ -1,12 +1,12 @@
|
|
1
1
|
|
2
|
-
%h1= @
|
3
|
-
%h1= title 'Member Login'
|
2
|
+
%h1= @page_title
|
4
3
|
.content= @article.text
|
5
|
-
%div= markdown(@article.body)
|
6
4
|
|
7
|
-
= form_for @article,
|
5
|
+
= form_for @article, :article_id => @article.id do |f|
|
8
6
|
= f.label :title, "Title"
|
9
|
-
= f.text_field :title
|
7
|
+
= f.text_field :title, :required => true
|
8
|
+
= f.label :text, "Description"
|
9
|
+
= f.text_field :text, :required => true
|
10
10
|
= f.label :body, "Body Content"
|
11
|
-
= f.
|
12
|
-
= f.submit
|
11
|
+
= f.text_area :body, rows: 10
|
12
|
+
= f.submit
|
@@ -11,7 +11,7 @@
|
|
11
11
|
- @articles.each do |article|
|
12
12
|
%tr
|
13
13
|
%td= article.user.code if article.user
|
14
|
-
%td= link_to article.title, :controller=>"articles", :action=>"show", :
|
14
|
+
%td= link_to article.title, :controller=>"articles", :action=>"show", :article_id=>article.id
|
15
15
|
%td= article.text
|
16
16
|
%td= article.created_at
|
17
17
|
%td= article.updated_at
|
@@ -20,4 +20,4 @@
|
|
20
20
|
- unless current_ma_user.role.upcase.split(',').include?("A")
|
21
21
|
- next unless article.user
|
22
22
|
- next unless current_ma_user == article.user
|
23
|
-
= link_to image_tag('delete.png', style:'border:none; float:none;'), "
|
23
|
+
= link_to image_tag('delete.png', style:'border:none; float:none;'), {controller: "articles", action: "destroy", article_id: article.id}, data: { confirm: "Please Confirm" }
|
@@ -1,7 +1,7 @@
|
|
1
1
|
- @title= "My Articles"
|
2
2
|
%p
|
3
3
|
- @page_title = 'All Articlces'
|
4
|
-
= paginate @
|
4
|
+
= paginate @my_articles
|
5
5
|
%table#article-table
|
6
6
|
%tr
|
7
7
|
%th Title
|
@@ -10,9 +10,9 @@
|
|
10
10
|
%th Updated
|
11
11
|
%th Delete
|
12
12
|
%th Edit
|
13
|
-
- @
|
13
|
+
- @my_articles.each do |article|
|
14
14
|
%tr
|
15
|
-
%td= link_to article.title, :controller=>"articles", :action=>"show", :
|
15
|
+
%td= link_to article.title, :controller=>"articles", :action=>"show", :article_id => article.id
|
16
16
|
%td= article.text.html_safe
|
17
17
|
%td= article.created_at.strftime('%m/%d/%Y')
|
18
18
|
%td= article.updated_at.strftime('%m/%d/%Y')
|
@@ -2,23 +2,24 @@
|
|
2
2
|
- description @article.text
|
3
3
|
- keywords @article.keywords
|
4
4
|
|
5
|
+
= link_to image_tag('pencil.png', style:'border:none; float:right;', id: 'article_pen'), {controller: "articles", action: "edit", article_id: @article.id}, data: { confirm: "Please Confirm" }
|
5
6
|
%div{"data-role" => "menu_mm", "data-theme" => "b", "data-backbtn"=>"false"}
|
6
7
|
#article-title= @article.title
|
7
8
|
|
8
9
|
#article-text= @article.body.html_safe
|
9
10
|
|
10
|
-
= link_to image_tag('pencil.png', style:'border:none; float:none;'), {controller: "jinda", action: "init", s: 'articles:xedit_article', article_id: @article.id}, data: { confirm: "Please Confirm" }
|
11
11
|
- @comments.each do |comment|
|
12
12
|
%div#article-comment.ui-corner-all
|
13
13
|
Author:
|
14
14
|
%b= comment.user.code if comment.user
|
15
15
|
%div#comment-body
|
16
16
|
%i= comment.body
|
17
|
-
|
17
|
+
-#
|
18
18
|
- if login?
|
19
19
|
%h3 Add a comment:
|
20
|
-
= form_for @article.comments.build
|
20
|
+
= form_for([@comment, @article.comments.build]) do |f|
|
21
21
|
= f.hidden_field :article_id, :value => @article.id
|
22
22
|
= f.label :body, "Comment"
|
23
23
|
= f.text_area :body
|
24
|
+
= f.hidden_field :user_id, :value => current_ma_user
|
24
25
|
= f.submit
|
@@ -4,7 +4,8 @@
|
|
4
4
|
%div{"data-role" => "header", "data-theme" => "b", "data-backbtn"=>"false"}
|
5
5
|
%h1= head
|
6
6
|
%div{"data-role" => "content", "data-id" => "menu_mm"}
|
7
|
-
%
|
7
|
+
%form.ui-filterable
|
8
|
+
%ul{"data-role" => "listview", "data-theme" => "g", "data-filter" => "true"}
|
8
9
|
%li
|
9
10
|
%a{"data-panel" => "main", "data-id" => "home", :href => "/jinda"} Home
|
10
11
|
= render :partial => "jinda/menu_mm"
|
@@ -1,43 +1,53 @@
|
|
1
|
-
.
|
1
|
+
.content-header
|
2
2
|
%div(style="text-align:center")
|
3
3
|
= image_tag "logo_jinda.png"
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
%
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
%
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
%
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
%
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
%
|
42
|
-
|
43
|
-
|
4
|
+
%ol.breadcrumb
|
5
|
+
%li.fa.fa-dashboard
|
6
|
+
Dashboard
|
7
|
+
.content
|
8
|
+
%div.row::before
|
9
|
+
%div.col-lg-3.col-xs-6
|
10
|
+
%div.small-box.bg-aqua
|
11
|
+
%div.inner
|
12
|
+
%b Current gems version found:
|
13
|
+
%ul
|
14
|
+
%li Ruby Version #{RUBY_VERSION }
|
15
|
+
%li Rails Version #{Rails.version }
|
16
|
+
%li gem jinda #{Gem.loaded_specs['jinda'].version}
|
17
|
+
%div.col-lg-3.col-xs-6
|
18
|
+
%div.small-box.bg-green
|
19
|
+
%div.inner
|
20
|
+
%b Recently tested with:
|
21
|
+
%ul
|
22
|
+
%li Rubygems 2.7.1
|
23
|
+
%li Rails 6.0.3
|
24
|
+
%div.col-lg-3.col-xs-6
|
25
|
+
%div.small-box.bg-yellow
|
26
|
+
%div.inner
|
27
|
+
%b Create New Rails:
|
28
|
+
%ul
|
29
|
+
%li rails new YOURAPP --skip-test-unit --skip-bundle --skip-active-record --skip-javascript --skip-turbolinks
|
30
|
+
%li (rails new YOURAPP -BOTJ)
|
31
|
+
%div.col-lg-3.col-xs-6
|
32
|
+
%div.small-box.bg-red
|
33
|
+
%div.inner
|
34
|
+
%b Installation
|
35
|
+
%ul
|
36
|
+
%li add gem 'jinda', '0.5.8' to Gemfile then $ bundle
|
37
|
+
%li rails generate jinda:install, then bundle
|
38
|
+
%li rails generate jinda:config
|
39
|
+
%li rails jinda:seed, will create initial user:password admin:secret
|
40
|
+
%li when update app/jinda/index.mm, run rake jinda:update
|
41
|
+
%div.col-lg-3.col-xs-6
|
42
|
+
%div.small-box.bg-blue
|
43
|
+
%div.inner
|
44
|
+
%b Option: Themes available: Jinda_adminbsb, Jinda_adminlte
|
45
|
+
%ul
|
46
|
+
%li To install gem 'jinda_adminlte'
|
47
|
+
%li Install
|
48
|
+
%li gem 'jinda_adminlte'
|
49
|
+
%li Then
|
50
|
+
%li $ bundle
|
51
|
+
%li $ rails generate jinda_adminlte:install
|
52
|
+
|
53
|
+
|
@@ -1,10 +1,10 @@
|
|
1
1
|
<head>
|
2
2
|
<%= favicon_link_tag %>
|
3
|
-
<%= csrf_meta_tags %>
|
4
|
-
<%= meta_tags %>
|
5
3
|
<meta name="description" content="Jinda" />
|
6
4
|
<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track":"reload" %>
|
7
5
|
<%= javascript_include_tag "application", "data-turbolinks-track": "reload" %>
|
8
6
|
<%= stylesheet_link_tag "jinda", "sarabun" %>
|
9
7
|
<script src = "https://ajax.aspnetcdn.com/ajax/jquery.validate/1.12.0/jquery.validate.js" ></script>
|
8
|
+
<%= csrf_meta_tags %>
|
9
|
+
<%= display_meta_tags %>
|
10
10
|
</head>
|
data/lib/jinda/helpers.rb
CHANGED
data/lib/jinda/version.rb
CHANGED
@@ -0,0 +1,1293 @@
|
|
1
|
+
/*!
|
2
|
+
* jQuery Validation Plugin v1.12.0
|
3
|
+
*
|
4
|
+
* http://jqueryvalidation.org/
|
5
|
+
*
|
6
|
+
* Copyright (c) 2014 Jörn Zaefferer
|
7
|
+
* Released under the MIT license
|
8
|
+
*/
|
9
|
+
(function($) {
|
10
|
+
|
11
|
+
$.extend($.fn, {
|
12
|
+
// http://jqueryvalidation.org/validate/
|
13
|
+
validate: function( options ) {
|
14
|
+
|
15
|
+
// if nothing is selected, return nothing; can't chain anyway
|
16
|
+
if ( !this.length ) {
|
17
|
+
if ( options && options.debug && window.console ) {
|
18
|
+
console.warn( "Nothing selected, can't validate, returning nothing." );
|
19
|
+
}
|
20
|
+
return;
|
21
|
+
}
|
22
|
+
|
23
|
+
// check if a validator for this form was already created
|
24
|
+
var validator = $.data( this[0], "validator" );
|
25
|
+
if ( validator ) {
|
26
|
+
return validator;
|
27
|
+
}
|
28
|
+
|
29
|
+
// Add novalidate tag if HTML5.
|
30
|
+
this.attr( "novalidate", "novalidate" );
|
31
|
+
|
32
|
+
validator = new $.validator( options, this[0] );
|
33
|
+
$.data( this[0], "validator", validator );
|
34
|
+
|
35
|
+
if ( validator.settings.onsubmit ) {
|
36
|
+
|
37
|
+
this.validateDelegate( ":submit", "click", function( event ) {
|
38
|
+
if ( validator.settings.submitHandler ) {
|
39
|
+
validator.submitButton = event.target;
|
40
|
+
}
|
41
|
+
// allow suppressing validation by adding a cancel class to the submit button
|
42
|
+
if ( $(event.target).hasClass("cancel") ) {
|
43
|
+
validator.cancelSubmit = true;
|
44
|
+
}
|
45
|
+
|
46
|
+
// allow suppressing validation by adding the html5 formnovalidate attribute to the submit button
|
47
|
+
if ( $(event.target).attr("formnovalidate") !== undefined ) {
|
48
|
+
validator.cancelSubmit = true;
|
49
|
+
}
|
50
|
+
});
|
51
|
+
|
52
|
+
// validate the form on submit
|
53
|
+
this.submit( function( event ) {
|
54
|
+
if ( validator.settings.debug ) {
|
55
|
+
// prevent form submit to be able to see console output
|
56
|
+
event.preventDefault();
|
57
|
+
}
|
58
|
+
function handle() {
|
59
|
+
var hidden;
|
60
|
+
if ( validator.settings.submitHandler ) {
|
61
|
+
if ( validator.submitButton ) {
|
62
|
+
// insert a hidden input as a replacement for the missing submit button
|
63
|
+
hidden = $("<input type='hidden'/>").attr("name", validator.submitButton.name).val( $(validator.submitButton).val() ).appendTo(validator.currentForm);
|
64
|
+
}
|
65
|
+
validator.settings.submitHandler.call( validator, validator.currentForm, event );
|
66
|
+
if ( validator.submitButton ) {
|
67
|
+
// and clean up afterwards; thanks to no-block-scope, hidden can be referenced
|
68
|
+
hidden.remove();
|
69
|
+
}
|
70
|
+
return false;
|
71
|
+
}
|
72
|
+
return true;
|
73
|
+
}
|
74
|
+
|
75
|
+
// prevent submit for invalid forms or custom submit handlers
|
76
|
+
if ( validator.cancelSubmit ) {
|
77
|
+
validator.cancelSubmit = false;
|
78
|
+
return handle();
|
79
|
+
}
|
80
|
+
if ( validator.form() ) {
|
81
|
+
if ( validator.pendingRequest ) {
|
82
|
+
validator.formSubmitted = true;
|
83
|
+
return false;
|
84
|
+
}
|
85
|
+
return handle();
|
86
|
+
} else {
|
87
|
+
validator.focusInvalid();
|
88
|
+
return false;
|
89
|
+
}
|
90
|
+
});
|
91
|
+
}
|
92
|
+
|
93
|
+
return validator;
|
94
|
+
},
|
95
|
+
// http://jqueryvalidation.org/valid/
|
96
|
+
valid: function() {
|
97
|
+
var valid, validator;
|
98
|
+
|
99
|
+
if ( $(this[0]).is("form")) {
|
100
|
+
valid = this.validate().form();
|
101
|
+
} else {
|
102
|
+
valid = true;
|
103
|
+
validator = $(this[0].form).validate();
|
104
|
+
this.each(function() {
|
105
|
+
valid = validator.element(this) && valid;
|
106
|
+
});
|
107
|
+
}
|
108
|
+
return valid;
|
109
|
+
},
|
110
|
+
// attributes: space separated list of attributes to retrieve and remove
|
111
|
+
removeAttrs: function( attributes ) {
|
112
|
+
var result = {},
|
113
|
+
$element = this;
|
114
|
+
$.each(attributes.split(/\s/), function( index, value ) {
|
115
|
+
result[value] = $element.attr(value);
|
116
|
+
$element.removeAttr(value);
|
117
|
+
});
|
118
|
+
return result;
|
119
|
+
},
|
120
|
+
// http://jqueryvalidation.org/rules/
|
121
|
+
rules: function( command, argument ) {
|
122
|
+
var element = this[0],
|
123
|
+
settings, staticRules, existingRules, data, param, filtered;
|
124
|
+
|
125
|
+
if ( command ) {
|
126
|
+
settings = $.data(element.form, "validator").settings;
|
127
|
+
staticRules = settings.rules;
|
128
|
+
existingRules = $.validator.staticRules(element);
|
129
|
+
switch (command) {
|
130
|
+
case "add":
|
131
|
+
$.extend(existingRules, $.validator.normalizeRule(argument));
|
132
|
+
// remove messages from rules, but allow them to be set separately
|
133
|
+
delete existingRules.messages;
|
134
|
+
staticRules[element.name] = existingRules;
|
135
|
+
if ( argument.messages ) {
|
136
|
+
settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages );
|
137
|
+
}
|
138
|
+
break;
|
139
|
+
case "remove":
|
140
|
+
if ( !argument ) {
|
141
|
+
delete staticRules[element.name];
|
142
|
+
return existingRules;
|
143
|
+
}
|
144
|
+
filtered = {};
|
145
|
+
$.each(argument.split(/\s/), function( index, method ) {
|
146
|
+
filtered[method] = existingRules[method];
|
147
|
+
delete existingRules[method];
|
148
|
+
if ( method === "required" ) {
|
149
|
+
$(element).removeAttr("aria-required");
|
150
|
+
}
|
151
|
+
});
|
152
|
+
return filtered;
|
153
|
+
}
|
154
|
+
}
|
155
|
+
|
156
|
+
data = $.validator.normalizeRules(
|
157
|
+
$.extend(
|
158
|
+
{},
|
159
|
+
$.validator.classRules(element),
|
160
|
+
$.validator.attributeRules(element),
|
161
|
+
$.validator.dataRules(element),
|
162
|
+
$.validator.staticRules(element)
|
163
|
+
), element);
|
164
|
+
|
165
|
+
// make sure required is at front
|
166
|
+
if ( data.required ) {
|
167
|
+
param = data.required;
|
168
|
+
delete data.required;
|
169
|
+
data = $.extend({ required: param }, data );
|
170
|
+
$(element).attr( "aria-required", "true" );
|
171
|
+
}
|
172
|
+
|
173
|
+
// make sure remote is at back
|
174
|
+
if ( data.remote ) {
|
175
|
+
param = data.remote;
|
176
|
+
delete data.remote;
|
177
|
+
data = $.extend( data, { remote: param });
|
178
|
+
}
|
179
|
+
|
180
|
+
return data;
|
181
|
+
}
|
182
|
+
});
|
183
|
+
|
184
|
+
// Custom selectors
|
185
|
+
$.extend($.expr[":"], {
|
186
|
+
// http://jqueryvalidation.org/blank-selector/
|
187
|
+
blank: function( a ) { return !$.trim("" + $(a).val()); },
|
188
|
+
// http://jqueryvalidation.org/filled-selector/
|
189
|
+
filled: function( a ) { return !!$.trim("" + $(a).val()); },
|
190
|
+
// http://jqueryvalidation.org/unchecked-selector/
|
191
|
+
unchecked: function( a ) { return !$(a).prop("checked"); }
|
192
|
+
});
|
193
|
+
|
194
|
+
// constructor for validator
|
195
|
+
$.validator = function( options, form ) {
|
196
|
+
this.settings = $.extend( true, {}, $.validator.defaults, options );
|
197
|
+
this.currentForm = form;
|
198
|
+
this.init();
|
199
|
+
};
|
200
|
+
|
201
|
+
// http://jqueryvalidation.org/jQuery.validator.format/
|
202
|
+
$.validator.format = function( source, params ) {
|
203
|
+
if ( arguments.length === 1 ) {
|
204
|
+
return function() {
|
205
|
+
var args = $.makeArray(arguments);
|
206
|
+
args.unshift(source);
|
207
|
+
return $.validator.format.apply( this, args );
|
208
|
+
};
|
209
|
+
}
|
210
|
+
if ( arguments.length > 2 && params.constructor !== Array ) {
|
211
|
+
params = $.makeArray(arguments).slice(1);
|
212
|
+
}
|
213
|
+
if ( params.constructor !== Array ) {
|
214
|
+
params = [ params ];
|
215
|
+
}
|
216
|
+
$.each(params, function( i, n ) {
|
217
|
+
source = source.replace( new RegExp("\\{" + i + "\\}", "g"), function() {
|
218
|
+
return n;
|
219
|
+
});
|
220
|
+
});
|
221
|
+
return source;
|
222
|
+
};
|
223
|
+
|
224
|
+
$.extend($.validator, {
|
225
|
+
|
226
|
+
defaults: {
|
227
|
+
messages: {},
|
228
|
+
groups: {},
|
229
|
+
rules: {},
|
230
|
+
errorClass: "error",
|
231
|
+
validClass: "valid",
|
232
|
+
errorElement: "label",
|
233
|
+
focusInvalid: true,
|
234
|
+
errorContainer: $([]),
|
235
|
+
errorLabelContainer: $([]),
|
236
|
+
onsubmit: true,
|
237
|
+
ignore: ":hidden",
|
238
|
+
ignoreTitle: false,
|
239
|
+
onfocusin: function( element ) {
|
240
|
+
this.lastActive = element;
|
241
|
+
|
242
|
+
// hide error label and remove error class on focus if enabled
|
243
|
+
if ( this.settings.focusCleanup && !this.blockFocusCleanup ) {
|
244
|
+
if ( this.settings.unhighlight ) {
|
245
|
+
this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );
|
246
|
+
}
|
247
|
+
this.addWrapper(this.errorsFor(element)).hide();
|
248
|
+
}
|
249
|
+
},
|
250
|
+
onfocusout: function( element ) {
|
251
|
+
if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) {
|
252
|
+
this.element(element);
|
253
|
+
}
|
254
|
+
},
|
255
|
+
onkeyup: function( element, event ) {
|
256
|
+
if ( event.which === 9 && this.elementValue(element) === "" ) {
|
257
|
+
return;
|
258
|
+
} else if ( element.name in this.submitted || element === this.lastElement ) {
|
259
|
+
this.element(element);
|
260
|
+
}
|
261
|
+
},
|
262
|
+
onclick: function( element ) {
|
263
|
+
// click on selects, radiobuttons and checkboxes
|
264
|
+
if ( element.name in this.submitted ) {
|
265
|
+
this.element(element);
|
266
|
+
|
267
|
+
// or option elements, check parent select in that case
|
268
|
+
} else if ( element.parentNode.name in this.submitted ) {
|
269
|
+
this.element(element.parentNode);
|
270
|
+
}
|
271
|
+
},
|
272
|
+
highlight: function( element, errorClass, validClass ) {
|
273
|
+
if ( element.type === "radio" ) {
|
274
|
+
this.findByName(element.name).addClass(errorClass).removeClass(validClass);
|
275
|
+
} else {
|
276
|
+
$(element).addClass(errorClass).removeClass(validClass);
|
277
|
+
}
|
278
|
+
},
|
279
|
+
unhighlight: function( element, errorClass, validClass ) {
|
280
|
+
if ( element.type === "radio" ) {
|
281
|
+
this.findByName(element.name).removeClass(errorClass).addClass(validClass);
|
282
|
+
} else {
|
283
|
+
$(element).removeClass(errorClass).addClass(validClass);
|
284
|
+
}
|
285
|
+
}
|
286
|
+
},
|
287
|
+
|
288
|
+
// http://jqueryvalidation.org/jQuery.validator.setDefaults/
|
289
|
+
setDefaults: function( settings ) {
|
290
|
+
$.extend( $.validator.defaults, settings );
|
291
|
+
},
|
292
|
+
|
293
|
+
messages: {
|
294
|
+
required: "This field is required.",
|
295
|
+
remote: "Please fix this field.",
|
296
|
+
email: "Please enter a valid email address.",
|
297
|
+
url: "Please enter a valid URL.",
|
298
|
+
date: "Please enter a valid date.",
|
299
|
+
dateISO: "Please enter a valid date (ISO).",
|
300
|
+
number: "Please enter a valid number.",
|
301
|
+
digits: "Please enter only digits.",
|
302
|
+
creditcard: "Please enter a valid credit card number.",
|
303
|
+
equalTo: "Please enter the same value again.",
|
304
|
+
maxlength: $.validator.format("Please enter no more than {0} characters."),
|
305
|
+
minlength: $.validator.format("Please enter at least {0} characters."),
|
306
|
+
rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."),
|
307
|
+
range: $.validator.format("Please enter a value between {0} and {1}."),
|
308
|
+
max: $.validator.format("Please enter a value less than or equal to {0}."),
|
309
|
+
min: $.validator.format("Please enter a value greater than or equal to {0}.")
|
310
|
+
},
|
311
|
+
|
312
|
+
autoCreateRanges: false,
|
313
|
+
|
314
|
+
prototype: {
|
315
|
+
|
316
|
+
init: function() {
|
317
|
+
this.labelContainer = $(this.settings.errorLabelContainer);
|
318
|
+
this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm);
|
319
|
+
this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer );
|
320
|
+
this.submitted = {};
|
321
|
+
this.valueCache = {};
|
322
|
+
this.pendingRequest = 0;
|
323
|
+
this.pending = {};
|
324
|
+
this.invalid = {};
|
325
|
+
this.reset();
|
326
|
+
|
327
|
+
var groups = (this.groups = {}),
|
328
|
+
rules;
|
329
|
+
$.each(this.settings.groups, function( key, value ) {
|
330
|
+
if ( typeof value === "string" ) {
|
331
|
+
value = value.split(/\s/);
|
332
|
+
}
|
333
|
+
$.each(value, function( index, name ) {
|
334
|
+
groups[name] = key;
|
335
|
+
});
|
336
|
+
});
|
337
|
+
rules = this.settings.rules;
|
338
|
+
$.each(rules, function( key, value ) {
|
339
|
+
rules[key] = $.validator.normalizeRule(value);
|
340
|
+
});
|
341
|
+
|
342
|
+
function delegate(event) {
|
343
|
+
var validator = $.data(this[0].form, "validator"),
|
344
|
+
eventType = "on" + event.type.replace(/^validate/, ""),
|
345
|
+
settings = validator.settings;
|
346
|
+
if ( settings[eventType] && !this.is( settings.ignore ) ) {
|
347
|
+
settings[eventType].call(validator, this[0], event);
|
348
|
+
}
|
349
|
+
}
|
350
|
+
$(this.currentForm)
|
351
|
+
.validateDelegate(":text, [type='password'], [type='file'], select, textarea, " +
|
352
|
+
"[type='number'], [type='search'] ,[type='tel'], [type='url'], " +
|
353
|
+
"[type='email'], [type='datetime'], [type='date'], [type='month'], " +
|
354
|
+
"[type='week'], [type='time'], [type='datetime-local'], " +
|
355
|
+
"[type='range'], [type='color'] ",
|
356
|
+
"focusin focusout keyup", delegate)
|
357
|
+
.validateDelegate("[type='radio'], [type='checkbox'], select, option", "click", delegate);
|
358
|
+
|
359
|
+
if ( this.settings.invalidHandler ) {
|
360
|
+
$(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler);
|
361
|
+
}
|
362
|
+
|
363
|
+
// Add aria-required to any Static/Data/Class required fields before first validation
|
364
|
+
// Screen readers require this attribute to be present before the initial submission http://www.w3.org/TR/WCAG-TECHS/ARIA2.html
|
365
|
+
$(this.currentForm).find("[required], [data-rule-required], .required").attr("aria-required", "true");
|
366
|
+
},
|
367
|
+
|
368
|
+
// http://jqueryvalidation.org/Validator.form/
|
369
|
+
form: function() {
|
370
|
+
this.checkForm();
|
371
|
+
$.extend(this.submitted, this.errorMap);
|
372
|
+
this.invalid = $.extend({}, this.errorMap);
|
373
|
+
if ( !this.valid() ) {
|
374
|
+
$(this.currentForm).triggerHandler("invalid-form", [ this ]);
|
375
|
+
}
|
376
|
+
this.showErrors();
|
377
|
+
return this.valid();
|
378
|
+
},
|
379
|
+
|
380
|
+
checkForm: function() {
|
381
|
+
this.prepareForm();
|
382
|
+
for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) {
|
383
|
+
this.check( elements[i] );
|
384
|
+
}
|
385
|
+
return this.valid();
|
386
|
+
},
|
387
|
+
|
388
|
+
// http://jqueryvalidation.org/Validator.element/
|
389
|
+
element: function( element ) {
|
390
|
+
var cleanElement = this.clean( element ),
|
391
|
+
checkElement = this.validationTargetFor( cleanElement ),
|
392
|
+
result = true;
|
393
|
+
|
394
|
+
this.lastElement = checkElement;
|
395
|
+
|
396
|
+
if ( checkElement === undefined ) {
|
397
|
+
delete this.invalid[ cleanElement.name ];
|
398
|
+
} else {
|
399
|
+
this.prepareElement( checkElement );
|
400
|
+
this.currentElements = $( checkElement );
|
401
|
+
|
402
|
+
result = this.check( checkElement ) !== false;
|
403
|
+
if (result) {
|
404
|
+
delete this.invalid[checkElement.name];
|
405
|
+
} else {
|
406
|
+
this.invalid[checkElement.name] = true;
|
407
|
+
}
|
408
|
+
}
|
409
|
+
// Add aria-invalid status for screen readers
|
410
|
+
$( element ).attr( "aria-invalid", !result );
|
411
|
+
|
412
|
+
if ( !this.numberOfInvalids() ) {
|
413
|
+
// Hide error containers on last error
|
414
|
+
this.toHide = this.toHide.add( this.containers );
|
415
|
+
}
|
416
|
+
this.showErrors();
|
417
|
+
return result;
|
418
|
+
},
|
419
|
+
|
420
|
+
// http://jqueryvalidation.org/Validator.showErrors/
|
421
|
+
showErrors: function( errors ) {
|
422
|
+
if ( errors ) {
|
423
|
+
// add items to error list and map
|
424
|
+
$.extend( this.errorMap, errors );
|
425
|
+
this.errorList = [];
|
426
|
+
for ( var name in errors ) {
|
427
|
+
this.errorList.push({
|
428
|
+
message: errors[name],
|
429
|
+
element: this.findByName(name)[0]
|
430
|
+
});
|
431
|
+
}
|
432
|
+
// remove items from success list
|
433
|
+
this.successList = $.grep( this.successList, function( element ) {
|
434
|
+
return !(element.name in errors);
|
435
|
+
});
|
436
|
+
}
|
437
|
+
if ( this.settings.showErrors ) {
|
438
|
+
this.settings.showErrors.call( this, this.errorMap, this.errorList );
|
439
|
+
} else {
|
440
|
+
this.defaultShowErrors();
|
441
|
+
}
|
442
|
+
},
|
443
|
+
|
444
|
+
// http://jqueryvalidation.org/Validator.resetForm/
|
445
|
+
resetForm: function() {
|
446
|
+
if ( $.fn.resetForm ) {
|
447
|
+
$(this.currentForm).resetForm();
|
448
|
+
}
|
449
|
+
this.submitted = {};
|
450
|
+
this.lastElement = null;
|
451
|
+
this.prepareForm();
|
452
|
+
this.hideErrors();
|
453
|
+
this.elements()
|
454
|
+
.removeClass( this.settings.errorClass )
|
455
|
+
.removeData( "previousValue" )
|
456
|
+
.removeAttr( "aria-invalid" );
|
457
|
+
},
|
458
|
+
|
459
|
+
numberOfInvalids: function() {
|
460
|
+
return this.objectLength(this.invalid);
|
461
|
+
},
|
462
|
+
|
463
|
+
objectLength: function( obj ) {
|
464
|
+
/* jshint unused: false */
|
465
|
+
var count = 0,
|
466
|
+
i;
|
467
|
+
for ( i in obj ) {
|
468
|
+
count++;
|
469
|
+
}
|
470
|
+
return count;
|
471
|
+
},
|
472
|
+
|
473
|
+
hideErrors: function() {
|
474
|
+
this.addWrapper( this.toHide ).hide();
|
475
|
+
},
|
476
|
+
|
477
|
+
valid: function() {
|
478
|
+
return this.size() === 0;
|
479
|
+
},
|
480
|
+
|
481
|
+
size: function() {
|
482
|
+
return this.errorList.length;
|
483
|
+
},
|
484
|
+
|
485
|
+
focusInvalid: function() {
|
486
|
+
if ( this.settings.focusInvalid ) {
|
487
|
+
try {
|
488
|
+
$(this.findLastActive() || this.errorList.length && this.errorList[0].element || [])
|
489
|
+
.filter(":visible")
|
490
|
+
.focus()
|
491
|
+
// manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
|
492
|
+
.trigger("focusin");
|
493
|
+
} catch(e) {
|
494
|
+
// ignore IE throwing errors when focusing hidden elements
|
495
|
+
}
|
496
|
+
}
|
497
|
+
},
|
498
|
+
|
499
|
+
findLastActive: function() {
|
500
|
+
var lastActive = this.lastActive;
|
501
|
+
return lastActive && $.grep(this.errorList, function( n ) {
|
502
|
+
return n.element.name === lastActive.name;
|
503
|
+
}).length === 1 && lastActive;
|
504
|
+
},
|
505
|
+
|
506
|
+
elements: function() {
|
507
|
+
var validator = this,
|
508
|
+
rulesCache = {};
|
509
|
+
|
510
|
+
// select all valid inputs inside the form (no submit or reset buttons)
|
511
|
+
return $(this.currentForm)
|
512
|
+
.find("input, select, textarea")
|
513
|
+
.not(":submit, :reset, :image, [disabled]")
|
514
|
+
.not( this.settings.ignore )
|
515
|
+
.filter(function() {
|
516
|
+
if ( !this.name && validator.settings.debug && window.console ) {
|
517
|
+
console.error( "%o has no name assigned", this);
|
518
|
+
}
|
519
|
+
|
520
|
+
// select only the first element for each name, and only those with rules specified
|
521
|
+
if ( this.name in rulesCache || !validator.objectLength($(this).rules()) ) {
|
522
|
+
return false;
|
523
|
+
}
|
524
|
+
|
525
|
+
rulesCache[this.name] = true;
|
526
|
+
return true;
|
527
|
+
});
|
528
|
+
},
|
529
|
+
|
530
|
+
clean: function( selector ) {
|
531
|
+
return $(selector)[0];
|
532
|
+
},
|
533
|
+
|
534
|
+
errors: function() {
|
535
|
+
var errorClass = this.settings.errorClass.split(" ").join(".");
|
536
|
+
return $(this.settings.errorElement + "." + errorClass, this.errorContext);
|
537
|
+
},
|
538
|
+
|
539
|
+
reset: function() {
|
540
|
+
this.successList = [];
|
541
|
+
this.errorList = [];
|
542
|
+
this.errorMap = {};
|
543
|
+
this.toShow = $([]);
|
544
|
+
this.toHide = $([]);
|
545
|
+
this.currentElements = $([]);
|
546
|
+
},
|
547
|
+
|
548
|
+
prepareForm: function() {
|
549
|
+
this.reset();
|
550
|
+
this.toHide = this.errors().add( this.containers );
|
551
|
+
},
|
552
|
+
|
553
|
+
prepareElement: function( element ) {
|
554
|
+
this.reset();
|
555
|
+
this.toHide = this.errorsFor(element);
|
556
|
+
},
|
557
|
+
|
558
|
+
elementValue: function( element ) {
|
559
|
+
var val,
|
560
|
+
$element = $(element),
|
561
|
+
type = $element.attr("type");
|
562
|
+
|
563
|
+
if ( type === "radio" || type === "checkbox" ) {
|
564
|
+
return $("input[name='" + $element.attr("name") + "']:checked").val();
|
565
|
+
}
|
566
|
+
|
567
|
+
val = $element.val();
|
568
|
+
if ( typeof val === "string" ) {
|
569
|
+
return val.replace(/\r/g, "");
|
570
|
+
}
|
571
|
+
return val;
|
572
|
+
},
|
573
|
+
|
574
|
+
check: function( element ) {
|
575
|
+
element = this.validationTargetFor( this.clean( element ) );
|
576
|
+
|
577
|
+
var rules = $(element).rules(),
|
578
|
+
rulesCount = $.map( rules, function(n, i) {
|
579
|
+
return i;
|
580
|
+
}).length,
|
581
|
+
dependencyMismatch = false,
|
582
|
+
val = this.elementValue(element),
|
583
|
+
result, method, rule;
|
584
|
+
|
585
|
+
for (method in rules ) {
|
586
|
+
rule = { method: method, parameters: rules[method] };
|
587
|
+
try {
|
588
|
+
|
589
|
+
result = $.validator.methods[method].call( this, val, element, rule.parameters );
|
590
|
+
|
591
|
+
// if a method indicates that the field is optional and therefore valid,
|
592
|
+
// don't mark it as valid when there are no other rules
|
593
|
+
if ( result === "dependency-mismatch" && rulesCount === 1 ) {
|
594
|
+
dependencyMismatch = true;
|
595
|
+
continue;
|
596
|
+
}
|
597
|
+
dependencyMismatch = false;
|
598
|
+
|
599
|
+
if ( result === "pending" ) {
|
600
|
+
this.toHide = this.toHide.not( this.errorsFor(element) );
|
601
|
+
return;
|
602
|
+
}
|
603
|
+
|
604
|
+
if ( !result ) {
|
605
|
+
this.formatAndAdd( element, rule );
|
606
|
+
return false;
|
607
|
+
}
|
608
|
+
} catch(e) {
|
609
|
+
if ( this.settings.debug && window.console ) {
|
610
|
+
console.log( "Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.", e );
|
611
|
+
}
|
612
|
+
throw e;
|
613
|
+
}
|
614
|
+
}
|
615
|
+
if ( dependencyMismatch ) {
|
616
|
+
return;
|
617
|
+
}
|
618
|
+
if ( this.objectLength(rules) ) {
|
619
|
+
this.successList.push(element);
|
620
|
+
}
|
621
|
+
return true;
|
622
|
+
},
|
623
|
+
|
624
|
+
// return the custom message for the given element and validation method
|
625
|
+
// specified in the element's HTML5 data attribute
|
626
|
+
// return the generic message if present and no method specific message is present
|
627
|
+
customDataMessage: function( element, method ) {
|
628
|
+
return $( element ).data( "msg" + method[ 0 ].toUpperCase() +
|
629
|
+
method.substring( 1 ).toLowerCase() ) || $( element ).data("msg");
|
630
|
+
},
|
631
|
+
|
632
|
+
// return the custom message for the given element name and validation method
|
633
|
+
customMessage: function( name, method ) {
|
634
|
+
var m = this.settings.messages[name];
|
635
|
+
return m && (m.constructor === String ? m : m[method]);
|
636
|
+
},
|
637
|
+
|
638
|
+
// return the first defined argument, allowing empty strings
|
639
|
+
findDefined: function() {
|
640
|
+
for (var i = 0; i < arguments.length; i++) {
|
641
|
+
if ( arguments[i] !== undefined ) {
|
642
|
+
return arguments[i];
|
643
|
+
}
|
644
|
+
}
|
645
|
+
return undefined;
|
646
|
+
},
|
647
|
+
|
648
|
+
defaultMessage: function( element, method ) {
|
649
|
+
return this.findDefined(
|
650
|
+
this.customMessage( element.name, method ),
|
651
|
+
this.customDataMessage( element, method ),
|
652
|
+
// title is never undefined, so handle empty string as undefined
|
653
|
+
!this.settings.ignoreTitle && element.title || undefined,
|
654
|
+
$.validator.messages[method],
|
655
|
+
"<strong>Warning: No message defined for " + element.name + "</strong>"
|
656
|
+
);
|
657
|
+
},
|
658
|
+
|
659
|
+
formatAndAdd: function( element, rule ) {
|
660
|
+
var message = this.defaultMessage( element, rule.method ),
|
661
|
+
theregex = /\$?\{(\d+)\}/g;
|
662
|
+
if ( typeof message === "function" ) {
|
663
|
+
message = message.call(this, rule.parameters, element);
|
664
|
+
} else if (theregex.test(message)) {
|
665
|
+
message = $.validator.format(message.replace(theregex, "{$1}"), rule.parameters);
|
666
|
+
}
|
667
|
+
this.errorList.push({
|
668
|
+
message: message,
|
669
|
+
element: element,
|
670
|
+
method: rule.method
|
671
|
+
});
|
672
|
+
|
673
|
+
this.errorMap[element.name] = message;
|
674
|
+
this.submitted[element.name] = message;
|
675
|
+
},
|
676
|
+
|
677
|
+
addWrapper: function( toToggle ) {
|
678
|
+
if ( this.settings.wrapper ) {
|
679
|
+
toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );
|
680
|
+
}
|
681
|
+
return toToggle;
|
682
|
+
},
|
683
|
+
|
684
|
+
defaultShowErrors: function() {
|
685
|
+
var i, elements, error;
|
686
|
+
for ( i = 0; this.errorList[i]; i++ ) {
|
687
|
+
error = this.errorList[i];
|
688
|
+
if ( this.settings.highlight ) {
|
689
|
+
this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
|
690
|
+
}
|
691
|
+
this.showLabel( error.element, error.message );
|
692
|
+
}
|
693
|
+
if ( this.errorList.length ) {
|
694
|
+
this.toShow = this.toShow.add( this.containers );
|
695
|
+
}
|
696
|
+
if ( this.settings.success ) {
|
697
|
+
for ( i = 0; this.successList[i]; i++ ) {
|
698
|
+
this.showLabel( this.successList[i] );
|
699
|
+
}
|
700
|
+
}
|
701
|
+
if ( this.settings.unhighlight ) {
|
702
|
+
for ( i = 0, elements = this.validElements(); elements[i]; i++ ) {
|
703
|
+
this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass );
|
704
|
+
}
|
705
|
+
}
|
706
|
+
this.toHide = this.toHide.not( this.toShow );
|
707
|
+
this.hideErrors();
|
708
|
+
this.addWrapper( this.toShow ).show();
|
709
|
+
},
|
710
|
+
|
711
|
+
validElements: function() {
|
712
|
+
return this.currentElements.not(this.invalidElements());
|
713
|
+
},
|
714
|
+
|
715
|
+
invalidElements: function() {
|
716
|
+
return $(this.errorList).map(function() {
|
717
|
+
return this.element;
|
718
|
+
});
|
719
|
+
},
|
720
|
+
|
721
|
+
showLabel: function( element, message ) {
|
722
|
+
var label = this.errorsFor( element );
|
723
|
+
if ( label.length ) {
|
724
|
+
// refresh error/success class
|
725
|
+
label.removeClass( this.settings.validClass ).addClass( this.settings.errorClass );
|
726
|
+
// replace message on existing label
|
727
|
+
label.html(message);
|
728
|
+
} else {
|
729
|
+
// create label
|
730
|
+
label = $("<" + this.settings.errorElement + ">")
|
731
|
+
.attr("for", this.idOrName(element))
|
732
|
+
.addClass(this.settings.errorClass)
|
733
|
+
.html(message || "");
|
734
|
+
if ( this.settings.wrapper ) {
|
735
|
+
// make sure the element is visible, even in IE
|
736
|
+
// actually showing the wrapped element is handled elsewhere
|
737
|
+
label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent();
|
738
|
+
}
|
739
|
+
if ( !this.labelContainer.append(label).length ) {
|
740
|
+
if ( this.settings.errorPlacement ) {
|
741
|
+
this.settings.errorPlacement(label, $(element) );
|
742
|
+
} else {
|
743
|
+
label.insertAfter(element);
|
744
|
+
}
|
745
|
+
}
|
746
|
+
}
|
747
|
+
if ( !message && this.settings.success ) {
|
748
|
+
label.text("");
|
749
|
+
if ( typeof this.settings.success === "string" ) {
|
750
|
+
label.addClass( this.settings.success );
|
751
|
+
} else {
|
752
|
+
this.settings.success( label, element );
|
753
|
+
}
|
754
|
+
}
|
755
|
+
this.toShow = this.toShow.add(label);
|
756
|
+
},
|
757
|
+
|
758
|
+
errorsFor: function( element ) {
|
759
|
+
var name = this.idOrName(element);
|
760
|
+
return this.errors().filter(function() {
|
761
|
+
return $(this).attr("for") === name;
|
762
|
+
});
|
763
|
+
},
|
764
|
+
|
765
|
+
idOrName: function( element ) {
|
766
|
+
return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name);
|
767
|
+
},
|
768
|
+
|
769
|
+
validationTargetFor: function( element ) {
|
770
|
+
// if radio/checkbox, validate first element in group instead
|
771
|
+
if ( this.checkable(element) ) {
|
772
|
+
element = this.findByName( element.name ).not(this.settings.ignore)[0];
|
773
|
+
}
|
774
|
+
return element;
|
775
|
+
},
|
776
|
+
|
777
|
+
checkable: function( element ) {
|
778
|
+
return (/radio|checkbox/i).test(element.type);
|
779
|
+
},
|
780
|
+
|
781
|
+
findByName: function( name ) {
|
782
|
+
return $(this.currentForm).find("[name='" + name + "']");
|
783
|
+
},
|
784
|
+
|
785
|
+
getLength: function( value, element ) {
|
786
|
+
switch ( element.nodeName.toLowerCase() ) {
|
787
|
+
case "select":
|
788
|
+
return $("option:selected", element).length;
|
789
|
+
case "input":
|
790
|
+
if ( this.checkable( element) ) {
|
791
|
+
return this.findByName(element.name).filter(":checked").length;
|
792
|
+
}
|
793
|
+
}
|
794
|
+
return value.length;
|
795
|
+
},
|
796
|
+
|
797
|
+
depend: function( param, element ) {
|
798
|
+
return this.dependTypes[typeof param] ? this.dependTypes[typeof param](param, element) : true;
|
799
|
+
},
|
800
|
+
|
801
|
+
dependTypes: {
|
802
|
+
"boolean": function( param ) {
|
803
|
+
return param;
|
804
|
+
},
|
805
|
+
"string": function( param, element ) {
|
806
|
+
return !!$(param, element.form).length;
|
807
|
+
},
|
808
|
+
"function": function( param, element ) {
|
809
|
+
return param(element);
|
810
|
+
}
|
811
|
+
},
|
812
|
+
|
813
|
+
optional: function( element ) {
|
814
|
+
var val = this.elementValue(element);
|
815
|
+
return !$.validator.methods.required.call(this, val, element) && "dependency-mismatch";
|
816
|
+
},
|
817
|
+
|
818
|
+
startRequest: function( element ) {
|
819
|
+
if ( !this.pending[element.name] ) {
|
820
|
+
this.pendingRequest++;
|
821
|
+
this.pending[element.name] = true;
|
822
|
+
}
|
823
|
+
},
|
824
|
+
|
825
|
+
stopRequest: function( element, valid ) {
|
826
|
+
this.pendingRequest--;
|
827
|
+
// sometimes synchronization fails, make sure pendingRequest is never < 0
|
828
|
+
if ( this.pendingRequest < 0 ) {
|
829
|
+
this.pendingRequest = 0;
|
830
|
+
}
|
831
|
+
delete this.pending[element.name];
|
832
|
+
if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) {
|
833
|
+
$(this.currentForm).submit();
|
834
|
+
this.formSubmitted = false;
|
835
|
+
} else if (!valid && this.pendingRequest === 0 && this.formSubmitted) {
|
836
|
+
$(this.currentForm).triggerHandler("invalid-form", [ this ]);
|
837
|
+
this.formSubmitted = false;
|
838
|
+
}
|
839
|
+
},
|
840
|
+
|
841
|
+
previousValue: function( element ) {
|
842
|
+
return $.data(element, "previousValue") || $.data(element, "previousValue", {
|
843
|
+
old: null,
|
844
|
+
valid: true,
|
845
|
+
message: this.defaultMessage( element, "remote" )
|
846
|
+
});
|
847
|
+
}
|
848
|
+
|
849
|
+
},
|
850
|
+
|
851
|
+
classRuleSettings: {
|
852
|
+
required: { required: true },
|
853
|
+
email: { email: true },
|
854
|
+
url: { url: true },
|
855
|
+
date: { date: true },
|
856
|
+
dateISO: { dateISO: true },
|
857
|
+
number: { number: true },
|
858
|
+
digits: { digits: true },
|
859
|
+
creditcard: { creditcard: true }
|
860
|
+
},
|
861
|
+
|
862
|
+
addClassRules: function( className, rules ) {
|
863
|
+
if ( className.constructor === String ) {
|
864
|
+
this.classRuleSettings[className] = rules;
|
865
|
+
} else {
|
866
|
+
$.extend(this.classRuleSettings, className);
|
867
|
+
}
|
868
|
+
},
|
869
|
+
|
870
|
+
classRules: function( element ) {
|
871
|
+
var rules = {},
|
872
|
+
classes = $(element).attr("class");
|
873
|
+
|
874
|
+
if ( classes ) {
|
875
|
+
$.each(classes.split(" "), function() {
|
876
|
+
if ( this in $.validator.classRuleSettings ) {
|
877
|
+
$.extend(rules, $.validator.classRuleSettings[this]);
|
878
|
+
}
|
879
|
+
});
|
880
|
+
}
|
881
|
+
return rules;
|
882
|
+
},
|
883
|
+
|
884
|
+
attributeRules: function( element ) {
|
885
|
+
var rules = {},
|
886
|
+
$element = $(element),
|
887
|
+
type = element.getAttribute("type"),
|
888
|
+
method, value;
|
889
|
+
|
890
|
+
for (method in $.validator.methods) {
|
891
|
+
|
892
|
+
// support for <input required> in both html5 and older browsers
|
893
|
+
if ( method === "required" ) {
|
894
|
+
value = element.getAttribute(method);
|
895
|
+
// Some browsers return an empty string for the required attribute
|
896
|
+
// and non-HTML5 browsers might have required="" markup
|
897
|
+
if ( value === "" ) {
|
898
|
+
value = true;
|
899
|
+
}
|
900
|
+
// force non-HTML5 browsers to return bool
|
901
|
+
value = !!value;
|
902
|
+
} else {
|
903
|
+
value = $element.attr(method);
|
904
|
+
}
|
905
|
+
|
906
|
+
// convert the value to a number for number inputs, and for text for backwards compability
|
907
|
+
// allows type="date" and others to be compared as strings
|
908
|
+
if ( /min|max/.test( method ) && ( type === null || /number|range|text/.test( type ) ) ) {
|
909
|
+
value = Number(value);
|
910
|
+
}
|
911
|
+
|
912
|
+
if ( value || value === 0 ) {
|
913
|
+
rules[method] = value;
|
914
|
+
} else if ( type === method && type !== "range" ) {
|
915
|
+
// exception: the jquery validate 'range' method
|
916
|
+
// does not test for the html5 'range' type
|
917
|
+
rules[method] = true;
|
918
|
+
}
|
919
|
+
}
|
920
|
+
|
921
|
+
// maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs
|
922
|
+
if ( rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength) ) {
|
923
|
+
delete rules.maxlength;
|
924
|
+
}
|
925
|
+
|
926
|
+
return rules;
|
927
|
+
},
|
928
|
+
|
929
|
+
dataRules: function( element ) {
|
930
|
+
var method, value,
|
931
|
+
rules = {}, $element = $( element );
|
932
|
+
for ( method in $.validator.methods ) {
|
933
|
+
value = $element.data( "rule" + method[ 0 ].toUpperCase() + method.substring( 1 ).toLowerCase() );
|
934
|
+
if ( value !== undefined ) {
|
935
|
+
rules[ method ] = value;
|
936
|
+
}
|
937
|
+
}
|
938
|
+
return rules;
|
939
|
+
},
|
940
|
+
|
941
|
+
staticRules: function( element ) {
|
942
|
+
var rules = {},
|
943
|
+
validator = $.data(element.form, "validator");
|
944
|
+
|
945
|
+
if ( validator.settings.rules ) {
|
946
|
+
rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {};
|
947
|
+
}
|
948
|
+
return rules;
|
949
|
+
},
|
950
|
+
|
951
|
+
normalizeRules: function( rules, element ) {
|
952
|
+
// handle dependency check
|
953
|
+
$.each(rules, function( prop, val ) {
|
954
|
+
// ignore rule when param is explicitly false, eg. required:false
|
955
|
+
if ( val === false ) {
|
956
|
+
delete rules[prop];
|
957
|
+
return;
|
958
|
+
}
|
959
|
+
if ( val.param || val.depends ) {
|
960
|
+
var keepRule = true;
|
961
|
+
switch (typeof val.depends) {
|
962
|
+
case "string":
|
963
|
+
keepRule = !!$(val.depends, element.form).length;
|
964
|
+
break;
|
965
|
+
case "function":
|
966
|
+
keepRule = val.depends.call(element, element);
|
967
|
+
break;
|
968
|
+
}
|
969
|
+
if ( keepRule ) {
|
970
|
+
rules[prop] = val.param !== undefined ? val.param : true;
|
971
|
+
} else {
|
972
|
+
delete rules[prop];
|
973
|
+
}
|
974
|
+
}
|
975
|
+
});
|
976
|
+
|
977
|
+
// evaluate parameters
|
978
|
+
$.each(rules, function( rule, parameter ) {
|
979
|
+
rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter;
|
980
|
+
});
|
981
|
+
|
982
|
+
// clean number parameters
|
983
|
+
$.each([ "minlength", "maxlength" ], function() {
|
984
|
+
if ( rules[this] ) {
|
985
|
+
rules[this] = Number(rules[this]);
|
986
|
+
}
|
987
|
+
});
|
988
|
+
$.each([ "rangelength", "range" ], function() {
|
989
|
+
var parts;
|
990
|
+
if ( rules[this] ) {
|
991
|
+
if ( $.isArray(rules[this]) ) {
|
992
|
+
rules[this] = [ Number(rules[this][0]), Number(rules[this][1]) ];
|
993
|
+
} else if ( typeof rules[this] === "string" ) {
|
994
|
+
parts = rules[this].split(/[\s,]+/);
|
995
|
+
rules[this] = [ Number(parts[0]), Number(parts[1]) ];
|
996
|
+
}
|
997
|
+
}
|
998
|
+
});
|
999
|
+
|
1000
|
+
if ( $.validator.autoCreateRanges ) {
|
1001
|
+
// auto-create ranges
|
1002
|
+
if ( rules.min && rules.max ) {
|
1003
|
+
rules.range = [ rules.min, rules.max ];
|
1004
|
+
delete rules.min;
|
1005
|
+
delete rules.max;
|
1006
|
+
}
|
1007
|
+
if ( rules.minlength && rules.maxlength ) {
|
1008
|
+
rules.rangelength = [ rules.minlength, rules.maxlength ];
|
1009
|
+
delete rules.minlength;
|
1010
|
+
delete rules.maxlength;
|
1011
|
+
}
|
1012
|
+
}
|
1013
|
+
|
1014
|
+
return rules;
|
1015
|
+
},
|
1016
|
+
|
1017
|
+
// Converts a simple string to a {string: true} rule, e.g., "required" to {required:true}
|
1018
|
+
normalizeRule: function( data ) {
|
1019
|
+
if ( typeof data === "string" ) {
|
1020
|
+
var transformed = {};
|
1021
|
+
$.each(data.split(/\s/), function() {
|
1022
|
+
transformed[this] = true;
|
1023
|
+
});
|
1024
|
+
data = transformed;
|
1025
|
+
}
|
1026
|
+
return data;
|
1027
|
+
},
|
1028
|
+
|
1029
|
+
// http://jqueryvalidation.org/jQuery.validator.addMethod/
|
1030
|
+
addMethod: function( name, method, message ) {
|
1031
|
+
$.validator.methods[name] = method;
|
1032
|
+
$.validator.messages[name] = message !== undefined ? message : $.validator.messages[name];
|
1033
|
+
if ( method.length < 3 ) {
|
1034
|
+
$.validator.addClassRules(name, $.validator.normalizeRule(name));
|
1035
|
+
}
|
1036
|
+
},
|
1037
|
+
|
1038
|
+
methods: {
|
1039
|
+
|
1040
|
+
// http://jqueryvalidation.org/required-method/
|
1041
|
+
required: function( value, element, param ) {
|
1042
|
+
// check if dependency is met
|
1043
|
+
if ( !this.depend(param, element) ) {
|
1044
|
+
return "dependency-mismatch";
|
1045
|
+
}
|
1046
|
+
if ( element.nodeName.toLowerCase() === "select" ) {
|
1047
|
+
// could be an array for select-multiple or a string, both are fine this way
|
1048
|
+
var val = $(element).val();
|
1049
|
+
return val && val.length > 0;
|
1050
|
+
}
|
1051
|
+
if ( this.checkable(element) ) {
|
1052
|
+
return this.getLength(value, element) > 0;
|
1053
|
+
}
|
1054
|
+
return $.trim(value).length > 0;
|
1055
|
+
},
|
1056
|
+
|
1057
|
+
// http://jqueryvalidation.org/email-method/
|
1058
|
+
email: function( value, element ) {
|
1059
|
+
// From http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#e-mail-state-%28type=email%29
|
1060
|
+
// Retrieved 2014-01-14
|
1061
|
+
// If you have a problem with this implementation, report a bug against the above spec
|
1062
|
+
// Or use custom methods to implement your own email validation
|
1063
|
+
return this.optional(element) || /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(value);
|
1064
|
+
},
|
1065
|
+
|
1066
|
+
// http://jqueryvalidation.org/url-method/
|
1067
|
+
url: function( value, element ) {
|
1068
|
+
// contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/
|
1069
|
+
return this.optional(element) || /^(https?|s?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);
|
1070
|
+
},
|
1071
|
+
|
1072
|
+
// http://jqueryvalidation.org/date-method/
|
1073
|
+
date: function( value, element ) {
|
1074
|
+
return this.optional(element) || !/Invalid|NaN/.test(new Date(value).toString());
|
1075
|
+
},
|
1076
|
+
|
1077
|
+
// http://jqueryvalidation.org/dateISO-method/
|
1078
|
+
dateISO: function( value, element ) {
|
1079
|
+
return this.optional(element) || /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/.test(value);
|
1080
|
+
},
|
1081
|
+
|
1082
|
+
// http://jqueryvalidation.org/number-method/
|
1083
|
+
number: function( value, element ) {
|
1084
|
+
return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value);
|
1085
|
+
},
|
1086
|
+
|
1087
|
+
// http://jqueryvalidation.org/digits-method/
|
1088
|
+
digits: function( value, element ) {
|
1089
|
+
return this.optional(element) || /^\d+$/.test(value);
|
1090
|
+
},
|
1091
|
+
|
1092
|
+
// http://jqueryvalidation.org/creditcard-method/
|
1093
|
+
// based on http://en.wikipedia.org/wiki/Luhn/
|
1094
|
+
creditcard: function( value, element ) {
|
1095
|
+
if ( this.optional(element) ) {
|
1096
|
+
return "dependency-mismatch";
|
1097
|
+
}
|
1098
|
+
// accept only spaces, digits and dashes
|
1099
|
+
if ( /[^0-9 \-]+/.test(value) ) {
|
1100
|
+
return false;
|
1101
|
+
}
|
1102
|
+
var nCheck = 0,
|
1103
|
+
nDigit = 0,
|
1104
|
+
bEven = false,
|
1105
|
+
n, cDigit;
|
1106
|
+
|
1107
|
+
value = value.replace(/\D/g, "");
|
1108
|
+
|
1109
|
+
// Basing min and max length on
|
1110
|
+
// http://developer.ean.com/general_info/Valid_Credit_Card_Types
|
1111
|
+
if ( value.length < 13 || value.length > 19 ) {
|
1112
|
+
return false;
|
1113
|
+
}
|
1114
|
+
|
1115
|
+
for ( n = value.length - 1; n >= 0; n--) {
|
1116
|
+
cDigit = value.charAt(n);
|
1117
|
+
nDigit = parseInt(cDigit, 10);
|
1118
|
+
if ( bEven ) {
|
1119
|
+
if ( (nDigit *= 2) > 9 ) {
|
1120
|
+
nDigit -= 9;
|
1121
|
+
}
|
1122
|
+
}
|
1123
|
+
nCheck += nDigit;
|
1124
|
+
bEven = !bEven;
|
1125
|
+
}
|
1126
|
+
|
1127
|
+
return (nCheck % 10) === 0;
|
1128
|
+
},
|
1129
|
+
|
1130
|
+
// http://jqueryvalidation.org/minlength-method/
|
1131
|
+
minlength: function( value, element, param ) {
|
1132
|
+
var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element);
|
1133
|
+
return this.optional(element) || length >= param;
|
1134
|
+
},
|
1135
|
+
|
1136
|
+
// http://jqueryvalidation.org/maxlength-method/
|
1137
|
+
maxlength: function( value, element, param ) {
|
1138
|
+
var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element);
|
1139
|
+
return this.optional(element) || length <= param;
|
1140
|
+
},
|
1141
|
+
|
1142
|
+
// http://jqueryvalidation.org/rangelength-method/
|
1143
|
+
rangelength: function( value, element, param ) {
|
1144
|
+
var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element);
|
1145
|
+
return this.optional(element) || ( length >= param[0] && length <= param[1] );
|
1146
|
+
},
|
1147
|
+
|
1148
|
+
// http://jqueryvalidation.org/min-method/
|
1149
|
+
min: function( value, element, param ) {
|
1150
|
+
return this.optional(element) || value >= param;
|
1151
|
+
},
|
1152
|
+
|
1153
|
+
// http://jqueryvalidation.org/max-method/
|
1154
|
+
max: function( value, element, param ) {
|
1155
|
+
return this.optional(element) || value <= param;
|
1156
|
+
},
|
1157
|
+
|
1158
|
+
// http://jqueryvalidation.org/range-method/
|
1159
|
+
range: function( value, element, param ) {
|
1160
|
+
return this.optional(element) || ( value >= param[0] && value <= param[1] );
|
1161
|
+
},
|
1162
|
+
|
1163
|
+
// http://jqueryvalidation.org/equalTo-method/
|
1164
|
+
equalTo: function( value, element, param ) {
|
1165
|
+
// bind to the blur event of the target in order to revalidate whenever the target field is updated
|
1166
|
+
// TODO find a way to bind the event just once, avoiding the unbind-rebind overhead
|
1167
|
+
var target = $(param);
|
1168
|
+
if ( this.settings.onfocusout ) {
|
1169
|
+
target.unbind(".validate-equalTo").bind("blur.validate-equalTo", function() {
|
1170
|
+
$(element).valid();
|
1171
|
+
});
|
1172
|
+
}
|
1173
|
+
return value === target.val();
|
1174
|
+
},
|
1175
|
+
|
1176
|
+
// http://jqueryvalidation.org/remote-method/
|
1177
|
+
remote: function( value, element, param ) {
|
1178
|
+
if ( this.optional(element) ) {
|
1179
|
+
return "dependency-mismatch";
|
1180
|
+
}
|
1181
|
+
|
1182
|
+
var previous = this.previousValue(element),
|
1183
|
+
validator, data;
|
1184
|
+
|
1185
|
+
if (!this.settings.messages[element.name] ) {
|
1186
|
+
this.settings.messages[element.name] = {};
|
1187
|
+
}
|
1188
|
+
previous.originalMessage = this.settings.messages[element.name].remote;
|
1189
|
+
this.settings.messages[element.name].remote = previous.message;
|
1190
|
+
|
1191
|
+
param = typeof param === "string" && { url: param } || param;
|
1192
|
+
|
1193
|
+
if ( previous.old === value ) {
|
1194
|
+
return previous.valid;
|
1195
|
+
}
|
1196
|
+
|
1197
|
+
previous.old = value;
|
1198
|
+
validator = this;
|
1199
|
+
this.startRequest(element);
|
1200
|
+
data = {};
|
1201
|
+
data[element.name] = value;
|
1202
|
+
$.ajax($.extend(true, {
|
1203
|
+
url: param,
|
1204
|
+
mode: "abort",
|
1205
|
+
port: "validate" + element.name,
|
1206
|
+
dataType: "json",
|
1207
|
+
data: data,
|
1208
|
+
context: validator.currentForm,
|
1209
|
+
success: function( response ) {
|
1210
|
+
var valid = response === true || response === "true",
|
1211
|
+
errors, message, submitted;
|
1212
|
+
|
1213
|
+
validator.settings.messages[element.name].remote = previous.originalMessage;
|
1214
|
+
if ( valid ) {
|
1215
|
+
submitted = validator.formSubmitted;
|
1216
|
+
validator.prepareElement(element);
|
1217
|
+
validator.formSubmitted = submitted;
|
1218
|
+
validator.successList.push(element);
|
1219
|
+
delete validator.invalid[element.name];
|
1220
|
+
validator.showErrors();
|
1221
|
+
} else {
|
1222
|
+
errors = {};
|
1223
|
+
message = response || validator.defaultMessage( element, "remote" );
|
1224
|
+
errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message;
|
1225
|
+
validator.invalid[element.name] = true;
|
1226
|
+
validator.showErrors(errors);
|
1227
|
+
}
|
1228
|
+
previous.valid = valid;
|
1229
|
+
validator.stopRequest(element, valid);
|
1230
|
+
}
|
1231
|
+
}, param));
|
1232
|
+
return "pending";
|
1233
|
+
}
|
1234
|
+
|
1235
|
+
}
|
1236
|
+
|
1237
|
+
});
|
1238
|
+
|
1239
|
+
$.format = function deprecated() {
|
1240
|
+
throw "$.format has been deprecated. Please use $.validator.format instead.";
|
1241
|
+
};
|
1242
|
+
|
1243
|
+
}(jQuery));
|
1244
|
+
|
1245
|
+
// ajax mode: abort
|
1246
|
+
// usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
|
1247
|
+
// if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()
|
1248
|
+
(function($) {
|
1249
|
+
var pendingRequests = {},
|
1250
|
+
ajax;
|
1251
|
+
// Use a prefilter if available (1.5+)
|
1252
|
+
if ( $.ajaxPrefilter ) {
|
1253
|
+
$.ajaxPrefilter(function( settings, _, xhr ) {
|
1254
|
+
var port = settings.port;
|
1255
|
+
if ( settings.mode === "abort" ) {
|
1256
|
+
if ( pendingRequests[port] ) {
|
1257
|
+
pendingRequests[port].abort();
|
1258
|
+
}
|
1259
|
+
pendingRequests[port] = xhr;
|
1260
|
+
}
|
1261
|
+
});
|
1262
|
+
} else {
|
1263
|
+
// Proxy ajax
|
1264
|
+
ajax = $.ajax;
|
1265
|
+
$.ajax = function( settings ) {
|
1266
|
+
var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode,
|
1267
|
+
port = ( "port" in settings ? settings : $.ajaxSettings ).port;
|
1268
|
+
if ( mode === "abort" ) {
|
1269
|
+
if ( pendingRequests[port] ) {
|
1270
|
+
pendingRequests[port].abort();
|
1271
|
+
}
|
1272
|
+
pendingRequests[port] = ajax.apply(this, arguments);
|
1273
|
+
return pendingRequests[port];
|
1274
|
+
}
|
1275
|
+
return ajax.apply(this, arguments);
|
1276
|
+
};
|
1277
|
+
}
|
1278
|
+
}(jQuery));
|
1279
|
+
|
1280
|
+
// provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation
|
1281
|
+
// handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target
|
1282
|
+
(function($) {
|
1283
|
+
$.extend($.fn, {
|
1284
|
+
validateDelegate: function( delegate, type, handler ) {
|
1285
|
+
return this.bind(type, function( event ) {
|
1286
|
+
var target = $(event.target);
|
1287
|
+
if ( target.is(delegate) ) {
|
1288
|
+
return handler.apply(target, arguments);
|
1289
|
+
}
|
1290
|
+
});
|
1291
|
+
}
|
1292
|
+
});
|
1293
|
+
}(jQuery));
|