├── .gitignore
├── .travis.yml
├── CONTRIBUTING.md
├── Gruntfile.js
├── LICENSE-MIT
├── README.md
├── component.json
├── dist
├── jqBootstrapValidation-1.3.7.js
├── jqBootstrapValidation-1.3.7.min.js
└── jqBootstrapValidation.zip
├── libs
├── jquery-loader.js
├── jquery
│ ├── jquery-1.8.2.js
│ ├── jquery-1.9.1.js
│ ├── jquery-1.9.1.min.js
│ ├── jquery-migrate.1.2.0.js
│ └── jquery.js
└── qunit
│ ├── qunit.css
│ └── qunit.js
├── package.json
├── src
└── jqBootstrapValidation.js
└── test
├── issues
├── 39
│ ├── 39.html
│ └── test.js
├── 47
│ ├── 47.html
│ └── test.js
└── 50
│ ├── 50.html
│ └── test.js
├── jqBootstrapValidation.html
├── jqBootstrapValidation_helpers.js
├── jqBootstrapValidation_test.js
└── notravis
└── 67
├── 67.html
└── test.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | tmp/
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "0.10"
4 | before_script:
5 | - npm install -g grunt-cli
6 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | ## Important notes
4 | Please don't edit files in the `dist` subdirectory as they are generated via grunt. You'll find source code in the `src` subdirectory!
5 |
6 | ## Modifying the code
7 | First, ensure that you have the latest [Node.js](http://nodejs.org/) and [npm](http://npmjs.org/) installed.
8 |
9 | Test that grunt is installed globally by running `grunt --version` at the command-line. If grunt isn't installed globally, run `npm install -g grunt` to install the latest version. _You may need to run `sudo npm install -g grunt`._
10 |
11 | _Note that in Windows, you may have to run `grunt.cmd` instead of `grunt`._
12 |
13 | 1. Fork and clone the repo.
14 | 1. Run `npm install` to install all dependencies (including grunt).
15 | 1. Run `grunt` to grunt this project.
16 |
17 | Assuming that you don't see any red, you're ready to go. Just be sure to run `grunt` after making any changes, to ensure that nothing is broken.
18 |
19 | ## Submitting pull requests
20 |
21 | 1. Create a new branch, please don't work in your `master` branch directly.
22 | 1. Add failing tests for the change you want to make. Run `grunt` to see the tests fail.
23 | 1. Fix stuff.
24 | 1. Run `grunt` to see if the tests pass. Repeat steps 2-4 until done.
25 | 1. Open `test/*.html` unit test file(s) in actual browser to ensure tests pass everywhere.
26 | 1. Update the documentation to reflect any changes.
27 | 1. Push to your fork and submit a pull request.
28 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | /*global module:false*/
2 | module.exports = function(grunt) {
3 |
4 | grunt.loadNpmTasks('grunt-contrib-concat');
5 | grunt.loadNpmTasks('grunt-contrib-compress');
6 | grunt.loadNpmTasks('grunt-contrib-clean');
7 | grunt.loadNpmTasks('grunt-contrib-uglify');
8 | grunt.loadNpmTasks('grunt-contrib-watch');
9 | grunt.loadNpmTasks('grunt-contrib-qunit');
10 | grunt.loadNpmTasks('grunt-contrib-jshint');
11 |
12 | // Project configuration.
13 | grunt.initConfig({
14 | pkg: grunt.file.readJSON('package.json'),
15 | meta: {
16 | banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
17 | '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
18 | '<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' +
19 | '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
20 | ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n',
21 | component: {
22 | name: '<%= pkg.name %>',
23 | version: '<%= pkg.version %>',
24 | main: ['./dist/<%= pkg.name %>-<%= pkg.version %>.min.js'],
25 | dependencies: {
26 | jquery: '*'
27 | }
28 | },
29 | },
30 | concat: {
31 | dist: {
32 | options: {
33 | banner: '<%= meta.banner %>',
34 | stripBanners: true
35 | },
36 | files: {
37 | 'dist/<%= pkg.name %>-<%= pkg.version %>.js': 'src/<%= pkg.name %>.js'
38 | }
39 | }
40 | },
41 | uglify: {
42 | dist: {
43 | options: {
44 | banner: '<%= meta.banner %>',
45 | },
46 | files: {
47 | 'dist/<%= pkg.name %>-<%= pkg.version %>.min.js': 'dist/<%= pkg.name %>-<%= pkg.version %>.js'
48 | }
49 | }
50 | },
51 | qunit: {
52 | local: ['test/notravis/**/*.html'],
53 | travis: ['test/issues/**/*.html', 'test/jqBootstrapValidation.html']
54 | },
55 | watch: {
56 | files: '<%= jshint.files %>',
57 | tasks: ['jshint', 'qunit']
58 | },
59 | jshint: {
60 | options: {
61 | curly: true,
62 | eqeqeq: true,
63 | immed: true,
64 | latedef: true,
65 | newcap: true,
66 | noarg: true,
67 | sub: true,
68 | undef: true,
69 | boss: true,
70 | eqnull: true,
71 | browser: true,
72 | globals: {
73 | jQuery: true
74 | },
75 | },
76 | files: ['Gruntfile.js', 'src/**/*.js', 'test/**/*.js']
77 | },
78 | compress: {
79 | dist: {
80 | options: {
81 | archive: 'dist/<%= pkg.name %>.zip'
82 | },
83 | expand: true,
84 | src: 'dist/*.js',
85 | flatten: true
86 | }
87 | },
88 | clean: {
89 | folder: "dist/"
90 | }
91 | });
92 |
93 | // Default task.
94 | grunt.registerTask('default', ['jshint', 'qunit', 'clean', 'concat', 'uglify', 'compress']);
95 |
96 | // Travis CI task.
97 | grunt.registerTask('travis', ['jshint', 'qunit:travis']);
98 |
99 | grunt.registerTask('component', 'Buld component.json', function () {
100 | var opts = grunt.config('meta.component');
101 |
102 | grunt.file.write('component.json', JSON.stringify(opts, true, 2) + '\n');
103 | });
104 |
105 | };
106 |
--------------------------------------------------------------------------------
/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013 David Godfrey
2 |
3 | Permission is hereby granted, free of charge, to any person
4 | obtaining a copy of this software and associated documentation
5 | files (the "Software"), to deal in the Software without
6 | restriction, including without limitation the rights to use,
7 | copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the
9 | Software is furnished to do so, subject to the following
10 | conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | jqBootstapValidation
2 | ====================
3 |
4 | A JQuery validation framework for bootstrap forms.
5 |
6 | Displays validation errors in `help-block` elements as users type.
7 |
8 | [](https://travis-ci.org/ReactiveRaven/jqBootstrapValidation)
9 |
10 | How to use?
11 | -----------
12 | The documentation is [here](https://reactiveraven.github.io/jqBootstrapValidation/).
13 |
14 | Developers
15 | ------------------
16 | Want to contribute? Great! Check out [CONTRIBUTING.md]
17 |
18 |
19 |
20 |
21 | [](http://coderwall.com/reactiveraven)
22 |
--------------------------------------------------------------------------------
/component.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jqBootstrapValidation",
3 | "version": "1.3.7",
4 | "main": ["./dist/jqBootstrapValidation-1.3.7.min.js"],
5 | "dependencies": {
6 | "jquery": "*"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/dist/jqBootstrapValidation-1.3.7.js:
--------------------------------------------------------------------------------
1 | /*! jqBootstrapValidation - v1.3.7 - 2013-05-07
2 | * http://reactiveraven.github.com/jqBootstrapValidation
3 | * Copyright (c) 2013 David Godfrey; Licensed MIT */
4 |
5 | (function( $ ){
6 |
7 | var createdElements = [];
8 |
9 | var defaults = {
10 | options: {
11 | prependExistingHelpBlock: false,
12 | sniffHtml: true, // sniff for 'required', 'maxlength', etc
13 | preventSubmit: true, // stop the form submit event from firing if validation fails
14 | submitError: false, // function called if there is an error when trying to submit
15 | submitSuccess: false, // function called just before a successful submit event is sent to the server
16 | semanticallyStrict: false, // set to true to tidy up generated HTML output
17 | bindEvents: [],
18 | autoAdd: {
19 | helpBlocks: true
20 | },
21 | filter: function () {
22 | // return $(this).is(":visible"); // only validate elements you can see
23 | return true; // validate everything
24 | }
25 | },
26 | methods: {
27 | init : function( options ) {
28 |
29 | // Get a clean copy of the defaults for extending
30 | var settings = $.extend(true, {}, defaults);
31 | // Set up the options based on the input
32 | settings.options = $.extend(true, settings.options, options);
33 |
34 | var $siblingElements = this;
35 |
36 | var uniqueForms = $.unique(
37 | $siblingElements.map( function () {
38 | return $(this).parents("form")[0];
39 | }).toArray()
40 | );
41 |
42 | $(uniqueForms).bind("submit.validationSubmit", function (e) {
43 | var $form = $(this);
44 | var warningsFound = 0;
45 | // Get all inputs
46 | var $allInputs = $form.find("input,textarea,select").not("[type=submit],[type=image]").filter(settings.options.filter);
47 | var $allControlGroups = $form.find(".control-group");
48 |
49 | // Only trigger validation on the ones that actually _have_ validation
50 | var $inputsWithValidators = $allInputs.filter(function () {
51 | return $(this).triggerHandler("getValidatorCount.validation") > 0;
52 | });
53 | $inputsWithValidators.trigger("submit.validation");
54 |
55 | // But all of them are out-of-focus now, because we're submitting.
56 | $allInputs.trigger("validationLostFocus.validation");
57 |
58 | // Okay, now check each controlgroup for errors (or warnings)
59 | $allControlGroups.each(function (i, el) {
60 | var $controlGroup = $(el);
61 | if ($controlGroup.hasClass("warning") || $controlGroup.hasClass("error")) {
62 | $controlGroup.removeClass("warning").addClass("error");
63 | warningsFound++;
64 | }
65 | });
66 |
67 | if (warningsFound) {
68 | // If we found any warnings, maybe we should prevent the submit
69 | // event, and trigger 'submitError' (if they're set up)
70 | if (settings.options.preventSubmit) {
71 | e.preventDefault();
72 | e.stopImmediatePropagation();
73 | }
74 | $form.addClass("error");
75 | if ($.isFunction(settings.options.submitError)) {
76 | settings.options.submitError($form, e, $inputsWithValidators.jqBootstrapValidation("collectErrors", true));
77 | }
78 | } else {
79 | // Woo! No errors! We can pass the submit event to submitSuccess
80 | // (if it has been set up)
81 | $form.removeClass("error");
82 | if ($.isFunction(settings.options.submitSuccess)) {
83 | settings.options.submitSuccess($form, e);
84 | }
85 | }
86 | });
87 |
88 | return this.each(function(){
89 |
90 | // Get references to everything we're interested in
91 | var $this = $(this),
92 | $controlGroup = $this.parents(".control-group").first(),
93 | $helpBlock = $controlGroup.find(".help-block").first(),
94 | $form = $this.parents("form").first(),
95 | validatorNames = [];
96 |
97 | // create message container if not exists
98 | if (!$helpBlock.length && settings.options.autoAdd && settings.options.autoAdd.helpBlocks) {
99 | $helpBlock = $('
');
100 | $controlGroup.find('.controls').append($helpBlock);
101 | createdElements.push($helpBlock[0]);
102 | }
103 |
104 | // =============================================================
105 | // SNIFF HTML FOR VALIDATORS
106 | // =============================================================
107 |
108 | // *snort sniff snuffle*
109 |
110 | if (settings.options.sniffHtml) {
111 | var message;
112 | // ---------------------------------------------------------
113 | // PATTERN
114 | // ---------------------------------------------------------
115 | if ($this.data("validationPatternPattern")) {
116 | $this.attr("pattern", $this.data("validationPatternPattern"));
117 | }
118 | if ($this.attr("pattern") !== undefined) {
119 | message = "Not in the expected format";
120 | if ($this.data("validationPatternMessage")) {
121 | message = $this.data("validationPatternMessage");
122 | }
123 | $this.data("validationPatternMessage", message);
124 | $this.data("validationPatternRegex", $this.attr("pattern"));
125 | }
126 | // ---------------------------------------------------------
127 | // MAX
128 | // ---------------------------------------------------------
129 | if ($this.attr("max") !== undefined || $this.attr("aria-valuemax") !== undefined) {
130 | var max = ($this.attr("max") !== undefined ? $this.attr("max") : $this.attr("aria-valuemax"));
131 | message = "Too high: Maximum of '" + max + "'";
132 | if ($this.data("validationMaxMessage")) {
133 | message = $this.data("validationMaxMessage");
134 | }
135 | $this.data("validationMaxMessage", message);
136 | $this.data("validationMaxMax", max);
137 | }
138 | // ---------------------------------------------------------
139 | // MIN
140 | // ---------------------------------------------------------
141 | if ($this.attr("min") !== undefined || $this.attr("aria-valuemin") !== undefined) {
142 | var min = ($this.attr("min") !== undefined ? $this.attr("min") : $this.attr("aria-valuemin"));
143 | message = "Too low: Minimum of '" + min + "'";
144 | if ($this.data("validationMinMessage")) {
145 | message = $this.data("validationMinMessage");
146 | }
147 | $this.data("validationMinMessage", message);
148 | $this.data("validationMinMin", min);
149 | }
150 | // ---------------------------------------------------------
151 | // MAXLENGTH
152 | // ---------------------------------------------------------
153 | if ($this.attr("maxlength") !== undefined) {
154 | message = "Too long: Maximum of '" + $this.attr("maxlength") + "' characters";
155 | if ($this.data("validationMaxlengthMessage")) {
156 | message = $this.data("validationMaxlengthMessage");
157 | }
158 | $this.data("validationMaxlengthMessage", message);
159 | $this.data("validationMaxlengthMaxlength", $this.attr("maxlength"));
160 | }
161 | // ---------------------------------------------------------
162 | // MINLENGTH
163 | // ---------------------------------------------------------
164 | if ($this.attr("minlength") !== undefined) {
165 | message = "Too short: Minimum of '" + $this.attr("minlength") + "' characters";
166 | if ($this.data("validationMinlengthMessage")) {
167 | message = $this.data("validationMinlengthMessage");
168 | }
169 | $this.data("validationMinlengthMessage", message);
170 | $this.data("validationMinlengthMinlength", $this.attr("minlength"));
171 | }
172 | // ---------------------------------------------------------
173 | // REQUIRED
174 | // ---------------------------------------------------------
175 | if ($this.attr("required") !== undefined || $this.attr("aria-required") !== undefined) {
176 | message = settings.builtInValidators.required.message;
177 | if ($this.data("validationRequiredMessage")) {
178 | message = $this.data("validationRequiredMessage");
179 | }
180 | $this.data("validationRequiredMessage", message);
181 | }
182 | // ---------------------------------------------------------
183 | // NUMBER
184 | // ---------------------------------------------------------
185 | if ($this.attr("type") !== undefined && $this.attr("type").toLowerCase() === "number") {
186 | message = settings.validatorTypes.number.message; // TODO: fix this
187 | if ($this.data("validationNumberMessage")) {
188 | message = $this.data("validationNumberMessage");
189 | }
190 | $this.data("validationNumberMessage", message);
191 |
192 | var step = settings.validatorTypes.number.step; // TODO: and this
193 | if ($this.data("validationNumberStep")) {
194 | step = $this.data("validationNumberStep");
195 | }
196 | $this.data("validationNumberStep", step);
197 |
198 | var decimal = settings.validatorTypes.number.decimal;
199 | if ($this.data("validationNumberDecimal")) {
200 | decimal = $this.data("validationNumberDecimal");
201 | }
202 | $this.data("validationNumberDecimal", decimal);
203 | }
204 | // ---------------------------------------------------------
205 | // EMAIL
206 | // ---------------------------------------------------------
207 | if ($this.attr("type") !== undefined && $this.attr("type").toLowerCase() === "email") {
208 | message = "Not a valid email address";
209 | if ($this.data("validationEmailMessage")) {
210 | message = $this.data("validationEmailMessage");
211 | }
212 | $this.data("validationEmailMessage", message);
213 | }
214 | // ---------------------------------------------------------
215 | // MINCHECKED
216 | // ---------------------------------------------------------
217 | if ($this.attr("minchecked") !== undefined) {
218 | message = "Not enough options checked; Minimum of '" + $this.attr("minchecked") + "' required";
219 | if ($this.data("validationMincheckedMessage")) {
220 | message = $this.data("validationMincheckedMessage");
221 | }
222 | $this.data("validationMincheckedMessage", message);
223 | $this.data("validationMincheckedMinchecked", $this.attr("minchecked"));
224 | }
225 | // ---------------------------------------------------------
226 | // MAXCHECKED
227 | // ---------------------------------------------------------
228 | if ($this.attr("maxchecked") !== undefined) {
229 | message = "Too many options checked; Maximum of '" + $this.attr("maxchecked") + "' required";
230 | if ($this.data("validationMaxcheckedMessage")) {
231 | message = $this.data("validationMaxcheckedMessage");
232 | }
233 | $this.data("validationMaxcheckedMessage", message);
234 | $this.data("validationMaxcheckedMaxchecked", $this.attr("maxchecked"));
235 | }
236 | }
237 |
238 | // =============================================================
239 | // COLLECT VALIDATOR NAMES
240 | // =============================================================
241 |
242 | // Get named validators
243 | if ($this.data("validation") !== undefined) {
244 | validatorNames = $this.data("validation").split(",");
245 | }
246 |
247 | // Get extra ones defined on the element's data attributes
248 | $.each($this.data(), function (i, el) {
249 | var parts = i.replace(/([A-Z])/g, ",$1").split(",");
250 | if (parts[0] === "validation" && parts[1]) {
251 | validatorNames.push(parts[1]);
252 | }
253 | });
254 |
255 | // =============================================================
256 | // NORMALISE VALIDATOR NAMES
257 | // =============================================================
258 |
259 | var validatorNamesToInspect = validatorNames;
260 | var newValidatorNamesToInspect = [];
261 |
262 | var uppercaseEachValidatorName = function (i, el) {
263 | validatorNames[i] = formatValidatorName(el);
264 | };
265 |
266 | var inspectValidators = function(i, el) {
267 | if ($this.data("validation" + el + "Shortcut") !== undefined) {
268 | // Are these custom validators?
269 | // Pull them out!
270 | $.each($this.data("validation" + el + "Shortcut").split(","), function(i2, el2) {
271 | newValidatorNamesToInspect.push(el2);
272 | });
273 | } else if (settings.builtInValidators[el.toLowerCase()]) {
274 | // Is this a recognised built-in?
275 | // Pull it out!
276 | var validator = settings.builtInValidators[el.toLowerCase()];
277 | if (validator.type.toLowerCase() === "shortcut") {
278 | $.each(validator.shortcut.split(","), function (i, el) {
279 | el = formatValidatorName(el);
280 | newValidatorNamesToInspect.push(el);
281 | validatorNames.push(el);
282 | });
283 | }
284 | }
285 | };
286 |
287 | do // repeatedly expand 'shortcut' validators into their real validators
288 | {
289 | // Uppercase only the first letter of each name
290 | $.each(validatorNames, uppercaseEachValidatorName);
291 |
292 | // Remove duplicate validator names
293 | validatorNames = $.unique(validatorNames);
294 |
295 | // Pull out the new validator names from each shortcut
296 | newValidatorNamesToInspect = [];
297 | $.each(validatorNamesToInspect, inspectValidators);
298 |
299 | validatorNamesToInspect = newValidatorNamesToInspect;
300 |
301 | } while (validatorNamesToInspect.length > 0);
302 |
303 | // =============================================================
304 | // SET UP VALIDATOR ARRAYS
305 | // =============================================================
306 |
307 | /* We're gonna generate something like
308 | *
309 | * {
310 | * "regex": [
311 | * { -- a validator object here --},
312 | * { -- a validator object here --}
313 | * ],
314 | * "required": [
315 | * { -- a validator object here --},
316 | * { -- a validator object here --}
317 | * ]
318 | * }
319 | *
320 | * with a few more entries.
321 | *
322 | * Because we only add a few validators to each field, most of the
323 | * keys will be empty arrays with no validator objects in them, and
324 | * thats fine.
325 | */
326 |
327 | var validators = {};
328 |
329 | $.each(validatorNames, function (i, el) {
330 | // Set up the 'override' message
331 | var message = $this.data("validation" + el + "Message");
332 | var hasOverrideMessage = !!message;
333 | var foundValidator = false;
334 | if (!message) {
335 | message = "'" + el + "' validation failed ";
336 | }
337 |
338 | $.each(
339 | settings.validatorTypes,
340 | function (validatorType, validatorTemplate) {
341 | if (validators[validatorType] === undefined) {
342 | validators[validatorType] = [];
343 | }
344 | if (!foundValidator && $this.data("validation" + el + formatValidatorName(validatorTemplate.name)) !== undefined) {
345 | var initted = validatorTemplate.init($this, el);
346 | if (hasOverrideMessage) {
347 | initted.message = message;
348 | }
349 |
350 | validators[validatorType].push(
351 | $.extend(
352 | true,
353 | {
354 | name: formatValidatorName(validatorTemplate.name),
355 | message: message
356 | },
357 | initted
358 | )
359 | );
360 | foundValidator = true;
361 | }
362 | }
363 | );
364 |
365 | if (!foundValidator && settings.builtInValidators[el.toLowerCase()]) {
366 |
367 | var validator = $.extend(true, {}, settings.builtInValidators[el.toLowerCase()]);
368 | if (hasOverrideMessage) {
369 | validator.message = message;
370 | }
371 | var validatorType = validator.type.toLowerCase();
372 |
373 | if (validatorType === "shortcut") {
374 | foundValidator = true;
375 | } else {
376 | $.each(
377 | settings.validatorTypes,
378 | function (validatorTemplateType, validatorTemplate) {
379 | if (validators[validatorTemplateType] === undefined) {
380 | validators[validatorTemplateType] = [];
381 | }
382 | if (!foundValidator && validatorType === validatorTemplateType.toLowerCase()) {
383 | $this.data(
384 | "validation" + el + formatValidatorName(validatorTemplate.name),
385 | validator[validatorTemplate.name.toLowerCase()]
386 | );
387 | validators[validatorType].push(
388 | $.extend(
389 | validator,
390 | validatorTemplate.init($this, el)
391 | )
392 | );
393 | foundValidator = true;
394 | }
395 | }
396 | );
397 | }
398 | }
399 |
400 | if (! foundValidator) {
401 | $.error("Cannot find validation info for '" + el + "'");
402 | }
403 | });
404 |
405 | // =============================================================
406 | // STORE FALLBACK VALUES
407 | // =============================================================
408 |
409 | $helpBlock.data(
410 | "original-contents",
411 | (
412 | $helpBlock.data("original-contents") ?
413 | $helpBlock.data("original-contents") :
414 | $helpBlock.html()
415 | )
416 | );
417 |
418 | $helpBlock.data(
419 | "original-role",
420 | (
421 | $helpBlock.data("original-role") ?
422 | $helpBlock.data("original-role") :
423 | $helpBlock.attr("role")
424 | )
425 | );
426 |
427 | $controlGroup.data(
428 | "original-classes",
429 | (
430 | $controlGroup.data("original-clases") ?
431 | $controlGroup.data("original-classes") :
432 | $controlGroup.attr("class")
433 | )
434 | );
435 |
436 | $this.data(
437 | "original-aria-invalid",
438 | (
439 | $this.data("original-aria-invalid") ?
440 | $this.data("original-aria-invalid") :
441 | $this.attr("aria-invalid")
442 | )
443 | );
444 |
445 | // =============================================================
446 | // VALIDATION
447 | // =============================================================
448 |
449 | $this.bind(
450 | "validation.validation",
451 | function (event, params) {
452 |
453 | var value = getValue($this);
454 |
455 | // Get a list of the errors to apply
456 | var errorsFound = [];
457 |
458 | $.each(validators, function (validatorType, validatorTypeArray) {
459 | if (
460 | value || // has a truthy value
461 | value.length || // not an empty string
462 | ( // am including empty values
463 | (
464 | params &&
465 | params.includeEmpty
466 | ) ||
467 | !!settings.validatorTypes[validatorType].includeEmpty
468 | ) ||
469 | ( // validator is blocking submit
470 | !!settings.validatorTypes[validatorType].blockSubmit &&
471 | params &&
472 | !!params.submitting
473 | )
474 | )
475 | {
476 | $.each(
477 | validatorTypeArray,
478 | function (i, validator) {
479 | if (settings.validatorTypes[validatorType].validate($this, value, validator)) {
480 | errorsFound.push(validator.message);
481 | }
482 | }
483 | );
484 | }
485 | });
486 |
487 | return errorsFound;
488 | }
489 | );
490 |
491 | $this.bind(
492 | "getValidators.validation",
493 | function () {
494 | return validators;
495 | }
496 | );
497 |
498 | var numValidators = 0;
499 |
500 | $.each(validators, function (i, el) {
501 | numValidators += el.length;
502 | });
503 |
504 | $this.bind("getValidatorCount.validation", function () {
505 | return numValidators;
506 | });
507 |
508 | // =============================================================
509 | // WATCH FOR CHANGES
510 | // =============================================================
511 | $this.bind(
512 | "submit.validation",
513 | function () {
514 | return $this.triggerHandler("change.validation", {submitting: true});
515 | }
516 | );
517 | $this.bind(
518 | (
519 | settings.options.bindEvents.length > 0 ?
520 | settings.options.bindEvents :
521 | [
522 | "keyup",
523 | "focus",
524 | "blur",
525 | "click",
526 | "keydown",
527 | "keypress",
528 | "change"
529 | ]
530 | ).concat(["revalidate"]).join(".validation ") + ".validation",
531 | function (e, params) {
532 |
533 | var value = getValue($this);
534 |
535 | var errorsFound = [];
536 |
537 | if (params && !!params.submitting) {
538 | $controlGroup.data("jqbvIsSubmitting", true);
539 | } else if (e.type !== "revalidate") {
540 | $controlGroup.data("jqbvIsSubmitting", false);
541 | }
542 |
543 | var formIsSubmitting = !!$controlGroup.data("jqbvIsSubmitting");
544 |
545 | $controlGroup.find("input,textarea,select").each(function (i, el) {
546 | var oldCount = errorsFound.length;
547 | $.each($(el).triggerHandler("validation.validation", params), function (j, message) {
548 | errorsFound.push(message);
549 | });
550 | if (errorsFound.length > oldCount) {
551 | $(el).attr("aria-invalid", "true");
552 | } else {
553 | var original = $this.data("original-aria-invalid");
554 | $(el).attr("aria-invalid", (original !== undefined ? original : false));
555 | }
556 | });
557 |
558 | $form.find("input,select,textarea").not($this).not("[name=\"" + $this.attr("name") + "\"]").trigger("validationLostFocus.validation");
559 |
560 | errorsFound = $.unique(errorsFound.sort());
561 |
562 | // Were there any errors?
563 | if (errorsFound.length) {
564 | // Better flag it up as a warning.
565 | $controlGroup.removeClass("success error warning").addClass(formIsSubmitting ? "error" : "warning");
566 |
567 | // How many errors did we find?
568 | if (settings.options.semanticallyStrict && errorsFound.length === 1) {
569 | // Only one? Being strict? Just output it.
570 | $helpBlock.html(errorsFound[0] +
571 | ( settings.options.prependExistingHelpBlock ? $helpBlock.data("original-contents") : "" ));
572 | } else {
573 | // Multiple? Being sloppy? Glue them together into an UL.
574 | $helpBlock.html("- " + errorsFound.join("
- ") + "
" +
575 | ( settings.options.prependExistingHelpBlock ? $helpBlock.data("original-contents") : "" ));
576 | }
577 | } else {
578 | $controlGroup.removeClass("warning error success");
579 | if (value.length > 0) {
580 | $controlGroup.addClass("success");
581 | }
582 | $helpBlock.html($helpBlock.data("original-contents"));
583 | }
584 |
585 | if (e.type === "blur") {
586 | $controlGroup.removeClass("success");
587 | }
588 | }
589 | );
590 | $this.bind("validationLostFocus.validation", function () {
591 | $controlGroup.removeClass("success");
592 | });
593 | });
594 | },
595 | destroy : function( ) {
596 |
597 | return this.each(
598 | function() {
599 |
600 | var
601 | $this = $(this),
602 | $controlGroup = $this.parents(".control-group").first(),
603 | $helpBlock = $controlGroup.find(".help-block").first(),
604 | $form = $this.parents("form").first();
605 |
606 | // remove our events
607 | $this.unbind('.validation'); // events are namespaced.
608 | $form.unbind(".validationSubmit");
609 | // reset help text
610 | $helpBlock.html($helpBlock.data("original-contents"));
611 | // reset classes
612 | $controlGroup.attr("class", $controlGroup.data("original-classes"));
613 | // reset aria
614 | $this.attr("aria-invalid", $this.data("original-aria-invalid"));
615 | // reset role
616 | $helpBlock.attr("role", $this.data("original-role"));
617 | // remove all elements we created
618 | if ($.inArray($helpBlock[0], createdElements) > -1) {
619 | $helpBlock.remove();
620 | }
621 |
622 | }
623 | );
624 |
625 | },
626 | collectErrors : function(includeEmpty) {
627 |
628 | var errorMessages = {};
629 | this.each(function (i, el) {
630 | var $el = $(el);
631 | var name = $el.attr("name");
632 | var errors = $el.triggerHandler("validation.validation", {includeEmpty: true});
633 | errorMessages[name] = $.extend(true, errors, errorMessages[name]);
634 | });
635 |
636 | $.each(errorMessages, function (i, el) {
637 | if (el.length === 0) {
638 | delete errorMessages[i];
639 | }
640 | });
641 |
642 | return errorMessages;
643 |
644 | },
645 | hasErrors: function() {
646 |
647 | var errorMessages = [];
648 |
649 | this.find('input,select,textarea').add(this).each(function (i, el) {
650 | errorMessages = errorMessages.concat(
651 | $(el).triggerHandler("getValidators.validation") ? $(el).triggerHandler("validation.validation", {submitting: true}) : []
652 | );
653 | });
654 |
655 | return (errorMessages.length > 0);
656 | },
657 | override : function (newDefaults) {
658 | defaults = $.extend(true, defaults, newDefaults);
659 | }
660 | },
661 | validatorTypes: {
662 | callback: {
663 | name: "callback",
664 | init: function($this, name) {
665 | var result = {
666 | validatorName: name,
667 | callback: $this.data("validation" + name + "Callback"),
668 | lastValue: $this.val(),
669 | lastValid: true,
670 | lastFinished: true
671 | };
672 |
673 | var message = "Not valid";
674 | if ($this.data("validation" + name + "Message")) {
675 | message = $this.data("validation" + name + "Message");
676 | }
677 | result.message = message;
678 |
679 | return result;
680 | },
681 | validate: function($this, value, validator) {
682 | if (validator.lastValue === value && validator.lastFinished) {
683 | return !validator.lastValid;
684 | }
685 |
686 | if (validator.lastFinished === true)
687 | {
688 | validator.lastValue = value;
689 | validator.lastValid = true;
690 | validator.lastFinished = false;
691 |
692 | var rrjqbvValidator = validator;
693 | var rrjqbvThis = $this;
694 | executeFunctionByName(
695 | validator.callback,
696 | window,
697 | $this,
698 | value,
699 | function(data) {
700 | if (rrjqbvValidator.lastValue === data.value) {
701 | rrjqbvValidator.lastValid = data.valid;
702 | if (data.message) {
703 | rrjqbvValidator.message = data.message;
704 | }
705 | rrjqbvValidator.lastFinished = true;
706 | rrjqbvThis.data(
707 | "validation" + rrjqbvValidator.validatorName + "Message",
708 | rrjqbvValidator.message
709 | );
710 |
711 | // Timeout is set to avoid problems with the events being considered 'already fired'
712 | setTimeout(function() {
713 | if (!$this.is(":focus") && $this.parents("form").first().data("jqbvIsSubmitting")) {
714 | rrjqbvThis.trigger("blur.validation");
715 | } else {
716 | rrjqbvThis.trigger("revalidate.validation");
717 | }
718 | }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst
719 | }
720 | }
721 | );
722 | }
723 |
724 | return false;
725 |
726 | }
727 | },
728 | ajax: {
729 | name: "ajax",
730 | init: function ($this, name) {
731 | return {
732 | validatorName: name,
733 | url: $this.data("validation" + name + "Ajax"),
734 | lastValue: $this.val(),
735 | lastValid: true,
736 | lastFinished: true
737 | };
738 | },
739 | validate: function ($this, value, validator) {
740 | if (""+validator.lastValue === ""+value && validator.lastFinished === true) {
741 | return validator.lastValid === false;
742 | }
743 |
744 | if (validator.lastFinished === true)
745 | {
746 | validator.lastValue = value;
747 | validator.lastValid = true;
748 | validator.lastFinished = false;
749 | $.ajax({
750 | url: validator.url,
751 | data: "value=" + encodeURIComponent(value) + "&field=" + $this.attr("name"),
752 | dataType: "json",
753 | success: function (data) {
754 | if (""+validator.lastValue === ""+data.value) {
755 | validator.lastValid = !!(data.valid);
756 | if (data.message) {
757 | validator.message = data.message;
758 | }
759 | validator.lastFinished = true;
760 | $this.data("validation" + validator.validatorName + "Message", validator.message);
761 | // Timeout is set to avoid problems with the events being considered 'already fired'
762 | setTimeout(function () {
763 | $this.trigger("revalidate.validation");
764 | }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst
765 | }
766 | },
767 | failure: function () {
768 | validator.lastValid = true;
769 | validator.message = "ajax call failed";
770 | validator.lastFinished = true;
771 | $this.data("validation" + validator.validatorName + "Message", validator.message);
772 | // Timeout is set to avoid problems with the events being considered 'already fired'
773 | setTimeout(function () {
774 | $this.trigger("revalidate.validation");
775 | }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst
776 | }
777 | });
778 | }
779 |
780 | return false;
781 |
782 | }
783 | },
784 | regex: {
785 | name: "regex",
786 | init: function ($this, name) {
787 | var result = {};
788 | var regexString = $this.data("validation" + name + "Regex");
789 | result.regex = regexFromString(regexString);
790 | if (regexString === undefined) {
791 | $.error("Can't find regex for '" + name + "' validator on '" + $this.attr("name") + "'");
792 | }
793 |
794 | var message = "Not in the expected format";
795 | if ($this.data("validation" + name + "Message")) {
796 | message = $this.data("validation" + name + "Message");
797 | }
798 |
799 | result.message = message;
800 |
801 | result.originalName = name;
802 | return result;
803 | },
804 | validate: function ($this, value, validator) {
805 | return (!validator.regex.test(value) && ! validator.negative) ||
806 | (validator.regex.test(value) && validator.negative);
807 | }
808 | },
809 | email: {
810 | name: "email",
811 | init: function ($this, name) {
812 | var result = {};
813 | result.regex = regexFromString('[a-zA-Z0-9.!#$%&\u2019*+/=?^_`{|}~-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}');
814 |
815 | var message = "Not a valid email address";
816 | if ($this.data("validation" + name + "Message")) {
817 | message = $this.data("validation" + name + "Message");
818 | }
819 |
820 | result.message = message;
821 |
822 | result.originalName = name;
823 | return result;
824 | },
825 | validate: function ($this, value, validator) {
826 | return (!validator.regex.test(value) && ! validator.negative) ||
827 | (validator.regex.test(value) && validator.negative);
828 | }
829 | },
830 | required: {
831 | name: "required",
832 | init: function ($this, name) {
833 | var message = "This is required";
834 | if ($this.data("validation" + name + "Message")) {
835 | message = $this.data("validation" + name + "Message");
836 | }
837 |
838 | return {message: message, includeEmpty: true};
839 | },
840 | validate: function ($this, value, validator) {
841 | return !!(
842 | (value.length === 0 && !validator.negative) ||
843 | (value.length > 0 && validator.negative)
844 | );
845 | },
846 | blockSubmit: true
847 | },
848 | match: {
849 | name: "match",
850 | init: function ($this, name) {
851 | var elementName = $this.data("validation" + name + "Match");
852 | var $form = $this.parents("form").first();
853 | var $element = $form.find("[name=\"" + elementName + "\"]").first();
854 | $element.bind("validation.validation", function () {
855 | $this.trigger("revalidate.validation", {submitting: true});
856 | });
857 | var result = {};
858 | result.element = $element;
859 |
860 | if ($element.length === 0) {
861 | $.error("Can't find field '" + elementName + "' to match '" + $this.attr("name") + "' against in '" + name + "' validator");
862 | }
863 |
864 | var message = "Must match";
865 | var $label = null;
866 | if (($label = $form.find("label[for=\"" + elementName + "\"]")).length) {
867 | message += " '" + $label.text() + "'";
868 | } else if (($label = $element.parents(".control-group").first().find("label")).length) {
869 | message += " '" + $label.first().text() + "'";
870 | }
871 |
872 | if ($this.data("validation" + name + "Message")) {
873 | message = $this.data("validation" + name + "Message");
874 | }
875 |
876 | result.message = message;
877 |
878 | return result;
879 | },
880 | validate: function ($this, value, validator) {
881 | return (value !== validator.element.val() && ! validator.negative) ||
882 | (value === validator.element.val() && validator.negative);
883 | },
884 | blockSubmit: true,
885 | includeEmpty: true
886 | },
887 | max: {
888 | name: "max",
889 | init: function ($this, name) {
890 | var result = {};
891 |
892 | result.max = $this.data("validation" + name + "Max");
893 |
894 | result.message = "Too high: Maximum of '" + result.max + "'";
895 | if ($this.data("validation" + name + "Message")) {
896 | result.message = $this.data("validation" + name + "Message");
897 | }
898 |
899 | return result;
900 | },
901 | validate: function ($this, value, validator) {
902 | return (parseFloat(value, 10) > parseFloat(validator.max, 10) && ! validator.negative) ||
903 | (parseFloat(value, 10) <= parseFloat(validator.max, 10) && validator.negative);
904 | }
905 | },
906 | min: {
907 | name: "min",
908 | init: function ($this, name) {
909 | var result = {};
910 |
911 | result.min = $this.data("validation" + name + "Min");
912 |
913 | result.message = "Too low: Minimum of '" + result.min + "'";
914 | if ($this.data("validation" + name + "Message")) {
915 | result.message = $this.data("validation" + name + "Message");
916 | }
917 |
918 | return result;
919 | },
920 | validate: function ($this, value, validator) {
921 | return (parseFloat(value) < parseFloat(validator.min) && ! validator.negative) ||
922 | (parseFloat(value) >= parseFloat(validator.min) && validator.negative);
923 | }
924 | },
925 | maxlength: {
926 | name: "maxlength",
927 | init: function ($this, name) {
928 | var result = {};
929 |
930 | result.maxlength = $this.data("validation" + name + "Maxlength");
931 |
932 | result.message = "Too long: Maximum of '" + result.maxlength + "' characters";
933 | if ($this.data("validation" + name + "Message")) {
934 | result.message = $this.data("validation" + name + "Message");
935 | }
936 |
937 | return result;
938 | },
939 | validate: function ($this, value, validator) {
940 | return ((value.length > validator.maxlength) && ! validator.negative) ||
941 | ((value.length <= validator.maxlength) && validator.negative);
942 | }
943 | },
944 | minlength: {
945 | name: "minlength",
946 | init: function ($this, name) {
947 | var result = {};
948 |
949 | result.minlength = $this.data("validation" + name + "Minlength");
950 |
951 | result.message = "Too short: Minimum of '" + result.minlength + "' characters";
952 | if ($this.data("validation" + name + "Message")) {
953 | result.message = $this.data("validation" + name + "Message");
954 | }
955 |
956 | return result;
957 | },
958 | validate: function ($this, value, validator) {
959 | return ((value.length < validator.minlength) && ! validator.negative) ||
960 | ((value.length >= validator.minlength) && validator.negative);
961 | }
962 | },
963 | maxchecked: {
964 | name: "maxchecked",
965 | init: function ($this, name) {
966 | var result = {};
967 |
968 | var elements = $this.parents("form").first().find("[name=\"" + $this.attr("name") + "\"]");
969 | elements.bind("change.validation click.validation", function () {
970 | $this.trigger("revalidate.validation", {includeEmpty: true});
971 | });
972 |
973 | result.elements = elements;
974 | result.maxchecked = $this.data("validation" + name + "Maxchecked");
975 |
976 | var message = "Too many: Max '" + result.maxchecked + "' checked";
977 | if ($this.data("validation" + name + "Message")) {
978 | message = $this.data("validation" + name + "Message");
979 | }
980 | result.message = message;
981 |
982 | return result;
983 | },
984 | validate: function ($this, value, validator) {
985 | return (validator.elements.filter(":checked").length > validator.maxchecked && ! validator.negative) ||
986 | (validator.elements.filter(":checked").length <= validator.maxchecked && validator.negative);
987 | },
988 | blockSubmit: true
989 | },
990 | minchecked: {
991 | name: "minchecked",
992 | init: function ($this, name) {
993 | var result = {};
994 |
995 | var elements = $this.parents("form").first().find("[name=\"" + $this.attr("name") + "\"]");
996 | elements.bind("change.validation click.validation", function () {
997 | $this.trigger("revalidate.validation", {includeEmpty: true});
998 | });
999 |
1000 | result.elements = elements;
1001 | result.minchecked = $this.data("validation" + name + "Minchecked");
1002 |
1003 | var message = "Too few: Min '" + result.minchecked + "' checked";
1004 | if ($this.data("validation" + name + "Message")) {
1005 | message = $this.data("validation" + name + "Message");
1006 | }
1007 | result.message = message;
1008 |
1009 | return result;
1010 | },
1011 | validate: function ($this, value, validator) {
1012 | return (validator.elements.filter(":checked").length < validator.minchecked && ! validator.negative) ||
1013 | (validator.elements.filter(":checked").length >= validator.minchecked && validator.negative);
1014 | },
1015 | blockSubmit: true,
1016 | includeEmpty: true
1017 | },
1018 | number: {
1019 | name: "number",
1020 | init: function ($this, name) {
1021 | var result = {};
1022 | result.step = 1;
1023 | if ($this.attr("step")) {
1024 | result.step = $this.attr("step");
1025 | }
1026 | if ($this.data("validation" + name + "Step")) {
1027 | result.step = $this.data("validation" + name + "Step");
1028 | }
1029 |
1030 | result.decimal = ".";
1031 | if ($this.data("validation" + name + "Decimal")) {
1032 | result.decimal = $this.data("validation" + name + "Decimal");
1033 | }
1034 |
1035 | result.thousands = "";
1036 | if ($this.data("validation" + name + "Thousands")) {
1037 | result.thousands = $this.data("validation" + name + "Thousands");
1038 | }
1039 |
1040 | result.regex = regexFromString("([+-]?\\d+(\\" + result.decimal + "\\d+)?)?");
1041 |
1042 | result.message = "Must be a number";
1043 | var dataMessage = $this.data("validation" + name + "Message");
1044 | if (dataMessage) {
1045 | result.message = dataMessage;
1046 | }
1047 |
1048 | return result;
1049 | },
1050 | validate: function ($this, value, validator) {
1051 | var globalValue = value.replace(validator.decimal, ".").replace(validator.thousands, "");
1052 | var multipliedValue = parseFloat(globalValue);
1053 | var multipliedStep = parseFloat(validator.step);
1054 | while (multipliedStep % 1 !== 0) {
1055 | /* thanks to @jkey #57 */
1056 | multipliedStep = parseFloat(multipliedStep.toPrecision(12)) * 10;
1057 | multipliedValue = parseFloat(multipliedValue.toPrecision(12)) * 10;
1058 | }
1059 | var regexResult = validator.regex.test(value);
1060 | var stepResult = parseFloat(multipliedValue) % parseFloat(multipliedStep) === 0;
1061 | var typeResult = !isNaN(parseFloat(globalValue)) && isFinite(globalValue);
1062 | var result = !(regexResult && stepResult && typeResult);
1063 | return result;
1064 | },
1065 | message: "Must be a number"
1066 | }
1067 | },
1068 | builtInValidators: {
1069 | email: {
1070 | name: "Email",
1071 | type: "email"
1072 | },
1073 | passwordagain: {
1074 | name: "Passwordagain",
1075 | type: "match",
1076 | match: "password",
1077 | message: "Does not match the given password"
1078 | },
1079 | positive: {
1080 | name: "Positive",
1081 | type: "shortcut",
1082 | shortcut: "number,positivenumber"
1083 | },
1084 | negative: {
1085 | name: "Negative",
1086 | type: "shortcut",
1087 | shortcut: "number,negativenumber"
1088 | },
1089 | integer: {
1090 | name: "Integer",
1091 | type: "regex",
1092 | regex: "[+-]?\\d+",
1093 | message: "No decimal places allowed"
1094 | },
1095 | positivenumber: {
1096 | name: "Positivenumber",
1097 | type: "min",
1098 | min: 0,
1099 | message: "Must be a positive number"
1100 | },
1101 | negativenumber: {
1102 | name: "Negativenumber",
1103 | type: "max",
1104 | max: 0,
1105 | message: "Must be a negative number"
1106 | },
1107 | required: {
1108 | name: "Required",
1109 | type: "required",
1110 | message: "This is required"
1111 | },
1112 | checkone: {
1113 | name: "Checkone",
1114 | type: "minchecked",
1115 | minchecked: 1,
1116 | message: "Check at least one option"
1117 | },
1118 | number: {
1119 | name: "Number",
1120 | type: "number",
1121 | decimal: ".",
1122 | step: "1"
1123 | },
1124 | pattern: {
1125 | name: "Pattern",
1126 | type: "regex",
1127 | message: "Not in expected format"
1128 | }
1129 | }
1130 | };
1131 |
1132 | var formatValidatorName = function (name) {
1133 | return name
1134 | .toLowerCase()
1135 | .replace(
1136 | /(^|\s)([a-z])/g ,
1137 | function(m,p1,p2) {
1138 | return p1+p2.toUpperCase();
1139 | }
1140 | )
1141 | ;
1142 | };
1143 |
1144 | var getValue = function ($this) {
1145 | // Extract the value we're talking about
1146 | var value = null;
1147 | var type = $this.attr("type");
1148 | if (type === "checkbox") {
1149 | value = ($this.is(":checked") ? value : "");
1150 | var checkboxParent = $this.parents("form").first() || $this.parents(".control-group").first();
1151 | if (checkboxParent) {
1152 | value = checkboxParent.find("input[name='" + $this.attr("name") + "']:checked").map(function (i, el) { return $(el).val(); }).toArray().join(",");
1153 | }
1154 | }
1155 | else if (type === "radio") {
1156 | value = ($('input[name="' + $this.attr("name") + '"]:checked').length > 0 ? $this.val() : "");
1157 | var radioParent = $this.parents("form").first() || $this.parents(".control-group").first();
1158 | if (radioParent) {
1159 | value = radioParent.find("input[name='" + $this.attr("name") + "']:checked").map(function (i, el) { return $(el).val(); }).toArray().join(",");
1160 | }
1161 | }
1162 | else {
1163 | value = $this.val();
1164 | }
1165 | return value;
1166 | };
1167 |
1168 | function regexFromString(inputstring) {
1169 | return new RegExp("^" + inputstring + "$");
1170 | }
1171 |
1172 | /**
1173 | * Thanks to Jason Bunting / Alex Nazarov via StackOverflow.com
1174 | *
1175 | * http://stackoverflow.com/a/4351575
1176 | **/
1177 | function executeFunctionByName(functionName, context /*, args */) {
1178 | var args = Array.prototype.slice.call(arguments, 2);
1179 | var namespaces = functionName.split(".");
1180 | var func = namespaces.pop();
1181 | for (var i = 0; i < namespaces.length; i++) {
1182 | context = context[namespaces[i]];
1183 | }
1184 | return context[func].apply(context, args);
1185 | }
1186 |
1187 | $.fn.jqBootstrapValidation = function( method ) {
1188 |
1189 | if ( defaults.methods[method] ) {
1190 | return defaults.methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
1191 | } else if ( typeof method === 'object' || ! method ) {
1192 | return defaults.methods.init.apply( this, arguments );
1193 | } else {
1194 | $.error( 'Method ' + method + ' does not exist on jQuery.jqBootstrapValidation' );
1195 | return null;
1196 | }
1197 |
1198 | };
1199 |
1200 | $.jqBootstrapValidation = function (options) {
1201 | $(":input").not("[type=image],[type=submit]").jqBootstrapValidation.apply(this,arguments);
1202 | };
1203 |
1204 | })( jQuery );
--------------------------------------------------------------------------------
/dist/jqBootstrapValidation-1.3.7.min.js:
--------------------------------------------------------------------------------
1 | /*! jqBootstrapValidation - v1.3.7 - 2013-05-07
2 | * http://reactiveraven.github.com/jqBootstrapValidation
3 | * Copyright (c) 2013 David Godfrey; Licensed MIT */
4 | (function(e){function s(e){return new RegExp("^"+e+"$")}function o(e,t){var n=Array.prototype.slice.call(arguments,2),r=e.split("."),i=r.pop();for(var s=0;s0});u.trigger("submit.validation"),i.trigger("validationLostFocus.validation"),s.each(function(t,n){var i=e(n);if(i.hasClass("warning")||i.hasClass("error"))i.removeClass("warning").addClass("error"),r++}),r?(o.options.preventSubmit&&(t.preventDefault(),t.stopImmediatePropagation()),n.addClass("error"),e.isFunction(o.options.submitError)&&o.options.submitError(n,t,u.jqBootstrapValidation("collectErrors",!0))):(n.removeClass("error"),e.isFunction(o.options.submitSuccess)&&o.options.submitSuccess(n,t))}),this.each(function(){var n=e(this),s=n.parents(".control-group").first(),u=s.find(".help-block").first(),a=n.parents("form").first(),f=[];!u.length&&o.options.autoAdd&&o.options.autoAdd.helpBlocks&&(u=e(''),s.find(".controls").append(u),t.push(u[0]));if(o.options.sniffHtml){var l;n.data("validationPatternPattern")&&n.attr("pattern",n.data("validationPatternPattern")),n.attr("pattern")!==undefined&&(l="Not in the expected format",n.data("validationPatternMessage")&&(l=n.data("validationPatternMessage")),n.data("validationPatternMessage",l),n.data("validationPatternRegex",n.attr("pattern")));if(n.attr("max")!==undefined||n.attr("aria-valuemax")!==undefined){var c=n.attr("max")!==undefined?n.attr("max"):n.attr("aria-valuemax");l="Too high: Maximum of '"+c+"'",n.data("validationMaxMessage")&&(l=n.data("validationMaxMessage")),n.data("validationMaxMessage",l),n.data("validationMaxMax",c)}if(n.attr("min")!==undefined||n.attr("aria-valuemin")!==undefined){var h=n.attr("min")!==undefined?n.attr("min"):n.attr("aria-valuemin");l="Too low: Minimum of '"+h+"'",n.data("validationMinMessage")&&(l=n.data("validationMinMessage")),n.data("validationMinMessage",l),n.data("validationMinMin",h)}n.attr("maxlength")!==undefined&&(l="Too long: Maximum of '"+n.attr("maxlength")+"' characters",n.data("validationMaxlengthMessage")&&(l=n.data("validationMaxlengthMessage")),n.data("validationMaxlengthMessage",l),n.data("validationMaxlengthMaxlength",n.attr("maxlength"))),n.attr("minlength")!==undefined&&(l="Too short: Minimum of '"+n.attr("minlength")+"' characters",n.data("validationMinlengthMessage")&&(l=n.data("validationMinlengthMessage")),n.data("validationMinlengthMessage",l),n.data("validationMinlengthMinlength",n.attr("minlength")));if(n.attr("required")!==undefined||n.attr("aria-required")!==undefined)l=o.builtInValidators.required.message,n.data("validationRequiredMessage")&&(l=n.data("validationRequiredMessage")),n.data("validationRequiredMessage",l);if(n.attr("type")!==undefined&&n.attr("type").toLowerCase()==="number"){l=o.validatorTypes.number.message,n.data("validationNumberMessage")&&(l=n.data("validationNumberMessage")),n.data("validationNumberMessage",l);var p=o.validatorTypes.number.step;n.data("validationNumberStep")&&(p=n.data("validationNumberStep")),n.data("validationNumberStep",p);var d=o.validatorTypes.number.decimal;n.data("validationNumberDecimal")&&(d=n.data("validationNumberDecimal")),n.data("validationNumberDecimal",d)}n.attr("type")!==undefined&&n.attr("type").toLowerCase()==="email"&&(l="Not a valid email address",n.data("validationEmailMessage")&&(l=n.data("validationEmailMessage")),n.data("validationEmailMessage",l)),n.attr("minchecked")!==undefined&&(l="Not enough options checked; Minimum of '"+n.attr("minchecked")+"' required",n.data("validationMincheckedMessage")&&(l=n.data("validationMincheckedMessage")),n.data("validationMincheckedMessage",l),n.data("validationMincheckedMinchecked",n.attr("minchecked"))),n.attr("maxchecked")!==undefined&&(l="Too many options checked; Maximum of '"+n.attr("maxchecked")+"' required",n.data("validationMaxcheckedMessage")&&(l=n.data("validationMaxcheckedMessage")),n.data("validationMaxcheckedMessage",l),n.data("validationMaxcheckedMaxchecked",n.attr("maxchecked")))}n.data("validation")!==undefined&&(f=n.data("validation").split(",")),e.each(n.data(),function(e,t){var n=e.replace(/([A-Z])/g,",$1").split(",");n[0]==="validation"&&n[1]&&f.push(n[1])});var v=f,m=[],g=function(e,t){f[e]=r(t)},y=function(t,i){if(n.data("validation"+i+"Shortcut")!==undefined)e.each(n.data("validation"+i+"Shortcut").split(","),function(e,t){m.push(t)});else if(o.builtInValidators[i.toLowerCase()]){var s=o.builtInValidators[i.toLowerCase()];s.type.toLowerCase()==="shortcut"&&e.each(s.shortcut.split(","),function(e,t){t=r(t),m.push(t),f.push(t)})}};do e.each(f,g),f=e.unique(f),m=[],e.each(v,y),v=m;while(v.length>0);var b={};e.each(f,function(t,i){var s=n.data("validation"+i+"Message"),u=!!s,a=!1;s||(s="'"+i+"' validation failed "),e.each(o.validatorTypes,function(t,o){b[t]===undefined&&(b[t]=[]);if(!a&&n.data("validation"+i+r(o.name))!==undefined){var f=o.init(n,i);u&&(f.message=s),b[t].push(e.extend(!0,{name:r(o.name),message:s},f)),a=!0}});if(!a&&o.builtInValidators[i.toLowerCase()]){var f=e.extend(!0,{},o.builtInValidators[i.toLowerCase()]);u&&(f.message=s);var l=f.type.toLowerCase();l==="shortcut"?a=!0:e.each(o.validatorTypes,function(t,s){b[t]===undefined&&(b[t]=[]),!a&&l===t.toLowerCase()&&(n.data("validation"+i+r(s.name),f[s.name.toLowerCase()]),b[l].push(e.extend(f,s.init(n,i))),a=!0)})}a||e.error("Cannot find validation info for '"+i+"'")}),u.data("original-contents",u.data("original-contents")?u.data("original-contents"):u.html()),u.data("original-role",u.data("original-role")?u.data("original-role"):u.attr("role")),s.data("original-classes",s.data("original-clases")?s.data("original-classes"):s.attr("class")),n.data("original-aria-invalid",n.data("original-aria-invalid")?n.data("original-aria-invalid"):n.attr("aria-invalid")),n.bind("validation.validation",function(t,r){var s=i(n),u=[];return e.each(b,function(t,i){(s||s.length||r&&r.includeEmpty||!!o.validatorTypes[t].includeEmpty||!!o.validatorTypes[t].blockSubmit&&r&&!!r.submitting)&&e.each(i,function(e,r){o.validatorTypes[t].validate(n,s,r)&&u.push(r.message)})}),u}),n.bind("getValidators.validation",function(){return b});var w=0;e.each(b,function(e,t){w+=t.length}),n.bind("getValidatorCount.validation",function(){return w}),n.bind("submit.validation",function(){return n.triggerHandler("change.validation",{submitting:!0})}),n.bind((o.options.bindEvents.length>0?o.options.bindEvents:["keyup","focus","blur","click","keydown","keypress","change"]).concat(["revalidate"]).join(".validation ")+".validation",function(t,r){var f=i(n),l=[];r&&!!r.submitting?s.data("jqbvIsSubmitting",!0):t.type!=="revalidate"&&s.data("jqbvIsSubmitting",!1);var c=!!s.data("jqbvIsSubmitting");s.find("input,textarea,select").each(function(t,i){var s=l.length;e.each(e(i).triggerHandler("validation.validation",r),function(e,t){l.push(t)});if(l.length>s)e(i).attr("aria-invalid","true");else{var o=n.data("original-aria-invalid");e(i).attr("aria-invalid",o!==undefined?o:!1)}}),a.find("input,select,textarea").not(n).not('[name="'+n.attr("name")+'"]').trigger("validationLostFocus.validation"),l=e.unique(l.sort()),l.length?(s.removeClass("success error warning").addClass(c?"error":"warning"),o.options.semanticallyStrict&&l.length===1?u.html(l[0]+(o.options.prependExistingHelpBlock?u.data("original-contents"):"")):u.html('"+(o.options.prependExistingHelpBlock?u.data("original-contents"):""))):(s.removeClass("warning error success"),f.length>0&&s.addClass("success"),u.html(u.data("original-contents"))),t.type==="blur"&&s.removeClass("success")}),n.bind("validationLostFocus.validation",function(){s.removeClass("success")})})},destroy:function(){return this.each(function(){var n=e(this),r=n.parents(".control-group").first(),i=r.find(".help-block").first(),s=n.parents("form").first();n.unbind(".validation"),s.unbind(".validationSubmit"),i.html(i.data("original-contents")),r.attr("class",r.data("original-classes")),n.attr("aria-invalid",n.data("original-aria-invalid")),i.attr("role",n.data("original-role")),e.inArray(i[0],t)>-1&&i.remove()})},collectErrors:function(t){var n={};return this.each(function(t,r){var i=e(r),s=i.attr("name"),o=i.triggerHandler("validation.validation",{includeEmpty:!0});n[s]=e.extend(!0,o,n[s])}),e.each(n,function(e,t){t.length===0&&delete n[e]}),n},hasErrors:function(){var t=[];return this.find("input,select,textarea").add(this).each(function(n,r){t=t.concat(e(r).triggerHandler("getValidators.validation")?e(r).triggerHandler("validation.validation",{submitting:!0}):[])}),t.length>0},override:function(t){n=e.extend(!0,n,t)}},validatorTypes:{callback:{name:"callback",init:function(e,t){var n={validatorName:t,callback:e.data("validation"+t+"Callback"),lastValue:e.val(),lastValid:!0,lastFinished:!0},r="Not valid";return e.data("validation"+t+"Message")&&(r=e.data("validation"+t+"Message")),n.message=r,n},validate:function(e,t,n){if(n.lastValue===t&&n.lastFinished)return!n.lastValid;if(n.lastFinished===!0){n.lastValue=t,n.lastValid=!0,n.lastFinished=!1;var r=n,i=e;o(n.callback,window,e,t,function(t){r.lastValue===t.value&&(r.lastValid=t.valid,t.message&&(r.message=t.message),r.lastFinished=!0,i.data("validation"+r.validatorName+"Message",r.message),setTimeout(function(){!e.is(":focus")&&e.parents("form").first().data("jqbvIsSubmitting")?i.trigger("blur.validation"):i.trigger("revalidate.validation")},1))})}return!1}},ajax:{name:"ajax",init:function(e,t){return{validatorName:t,url:e.data("validation"+t+"Ajax"),lastValue:e.val(),lastValid:!0,lastFinished:!0}},validate:function(t,n,r){return""+r.lastValue==""+n&&r.lastFinished===!0?r.lastValid===!1:(r.lastFinished===!0&&(r.lastValue=n,r.lastValid=!0,r.lastFinished=!1,e.ajax({url:r.url,data:"value="+encodeURIComponent(n)+"&field="+t.attr("name"),dataType:"json",success:function(e){""+r.lastValue==""+e.value&&(r.lastValid=!!e.valid,e.message&&(r.message=e.message),r.lastFinished=!0,t.data("validation"+r.validatorName+"Message",r.message),setTimeout(function(){t.trigger("revalidate.validation")},1))},failure:function(){r.lastValid=!0,r.message="ajax call failed",r.lastFinished=!0,t.data("validation"+r.validatorName+"Message",r.message),setTimeout(function(){t.trigger("revalidate.validation")},1)}})),!1)}},regex:{name:"regex",init:function(t,n){var r={},i=t.data("validation"+n+"Regex");r.regex=s(i),i===undefined&&e.error("Can't find regex for '"+n+"' validator on '"+t.attr("name")+"'");var o="Not in the expected format";return t.data("validation"+n+"Message")&&(o=t.data("validation"+n+"Message")),r.message=o,r.originalName=n,r},validate:function(e,t,n){return!n.regex.test(t)&&!n.negative||n.regex.test(t)&&n.negative}},email:{name:"email",init:function(e,t){var n={};n.regex=s("[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}");var r="Not a valid email address";return e.data("validation"+t+"Message")&&(r=e.data("validation"+t+"Message")),n.message=r,n.originalName=t,n},validate:function(e,t,n){return!n.regex.test(t)&&!n.negative||n.regex.test(t)&&n.negative}},required:{name:"required",init:function(e,t){var n="This is required";return e.data("validation"+t+"Message")&&(n=e.data("validation"+t+"Message")),{message:n,includeEmpty:!0}},validate:function(e,t,n){return!!(t.length===0&&!n.negative||t.length>0&&n.negative)},blockSubmit:!0},match:{name:"match",init:function(t,n){var r=t.data("validation"+n+"Match"),i=t.parents("form").first(),s=i.find('[name="'+r+'"]').first();s.bind("validation.validation",function(){t.trigger("revalidate.validation",{submitting:!0})});var o={};o.element=s,s.length===0&&e.error("Can't find field '"+r+"' to match '"+t.attr("name")+"' against in '"+n+"' validator");var u="Must match",a=null;return(a=i.find('label[for="'+r+'"]')).length?u+=" '"+a.text()+"'":(a=s.parents(".control-group").first().find("label")).length&&(u+=" '"+a.first().text()+"'"),t.data("validation"+n+"Message")&&(u=t.data("validation"+n+"Message")),o.message=u,o},validate:function(e,t,n){return t!==n.element.val()&&!n.negative||t===n.element.val()&&n.negative},blockSubmit:!0,includeEmpty:!0},max:{name:"max",init:function(e,t){var n={};return n.max=e.data("validation"+t+"Max"),n.message="Too high: Maximum of '"+n.max+"'",e.data("validation"+t+"Message")&&(n.message=e.data("validation"+t+"Message")),n},validate:function(e,t,n){return parseFloat(t,10)>parseFloat(n.max,10)&&!n.negative||parseFloat(t,10)<=parseFloat(n.max,10)&&n.negative}},min:{name:"min",init:function(e,t){var n={};return n.min=e.data("validation"+t+"Min"),n.message="Too low: Minimum of '"+n.min+"'",e.data("validation"+t+"Message")&&(n.message=e.data("validation"+t+"Message")),n},validate:function(e,t,n){return parseFloat(t)=parseFloat(n.min)&&n.negative}},maxlength:{name:"maxlength",init:function(e,t){var n={};return n.maxlength=e.data("validation"+t+"Maxlength"),n.message="Too long: Maximum of '"+n.maxlength+"' characters",e.data("validation"+t+"Message")&&(n.message=e.data("validation"+t+"Message")),n},validate:function(e,t,n){return t.length>n.maxlength&&!n.negative||t.length<=n.maxlength&&n.negative}},minlength:{name:"minlength",init:function(e,t){var n={};return n.minlength=e.data("validation"+t+"Minlength"),n.message="Too short: Minimum of '"+n.minlength+"' characters",e.data("validation"+t+"Message")&&(n.message=e.data("validation"+t+"Message")),n},validate:function(e,t,n){return t.length=n.minlength&&n.negative}},maxchecked:{name:"maxchecked",init:function(e,t){var n={},r=e.parents("form").first().find('[name="'+e.attr("name")+'"]');r.bind("change.validation click.validation",function(){e.trigger("revalidate.validation",{includeEmpty:!0})}),n.elements=r,n.maxchecked=e.data("validation"+t+"Maxchecked");var i="Too many: Max '"+n.maxchecked+"' checked";return e.data("validation"+t+"Message")&&(i=e.data("validation"+t+"Message")),n.message=i,n},validate:function(e,t,n){return n.elements.filter(":checked").length>n.maxchecked&&!n.negative||n.elements.filter(":checked").length<=n.maxchecked&&n.negative},blockSubmit:!0},minchecked:{name:"minchecked",init:function(e,t){var n={},r=e.parents("form").first().find('[name="'+e.attr("name")+'"]');r.bind("change.validation click.validation",function(){e.trigger("revalidate.validation",{includeEmpty:!0})}),n.elements=r,n.minchecked=e.data("validation"+t+"Minchecked");var i="Too few: Min '"+n.minchecked+"' checked";return e.data("validation"+t+"Message")&&(i=e.data("validation"+t+"Message")),n.message=i,n},validate:function(e,t,n){return n.elements.filter(":checked").length=n.minchecked&&n.negative},blockSubmit:!0,includeEmpty:!0},number:{name:"number",init:function(e,t){var n={};n.step=1,e.attr("step")&&(n.step=e.attr("step")),e.data("validation"+t+"Step")&&(n.step=e.data("validation"+t+"Step")),n.decimal=".",e.data("validation"+t+"Decimal")&&(n.decimal=e.data("validation"+t+"Decimal")),n.thousands="",e.data("validation"+t+"Thousands")&&(n.thousands=e.data("validation"+t+"Thousands")),n.regex=s("([+-]?\\d+(\\"+n.decimal+"\\d+)?)?"),n.message="Must be a number";var r=e.data("validation"+t+"Message");return r&&(n.message=r),n},validate:function(e,t,n){var r=t.replace(n.decimal,".").replace(n.thousands,""),i=parseFloat(r),s=parseFloat(n.step);while(s%1!==0)s=parseFloat(s.toPrecision(12))*10,i=parseFloat(i.toPrecision(12))*10;var o=n.regex.test(t),u=parseFloat(i)%parseFloat(s)===0,a=!isNaN(parseFloat(r))&&isFinite(r),f=!(o&&u&&a);return f},message:"Must be a number"}},builtInValidators:{email:{name:"Email",type:"email"},passwordagain:{name:"Passwordagain",type:"match",match:"password",message:"Does not match the given password"},positive:{name:"Positive",type:"shortcut",shortcut:"number,positivenumber"},negative:{name:"Negative",type:"shortcut",shortcut:"number,negativenumber"},integer:{name:"Integer",type:"regex",regex:"[+-]?\\d+",message:"No decimal places allowed"},positivenumber:{name:"Positivenumber",type:"min",min:0,message:"Must be a positive number"},negativenumber:{name:"Negativenumber",type:"max",max:0,message:"Must be a negative number"},required:{name:"Required",type:"required",message:"This is required"},checkone:{name:"Checkone",type:"minchecked",minchecked:1,message:"Check at least one option"},number:{name:"Number",type:"number",decimal:".",step:"1"},pattern:{name:"Pattern",type:"regex",message:"Not in expected format"}}},r=function(e){return e.toLowerCase().replace(/(^|\s)([a-z])/g,function(e,t,n){return t+n.toUpperCase()})},i=function(t){var n=null,r=t.attr("type");if(r==="checkbox"){n=t.is(":checked")?n:"";var i=t.parents("form").first()||t.parents(".control-group").first();i&&(n=i.find("input[name='"+t.attr("name")+"']:checked").map(function(t,n){return e(n).val()}).toArray().join(","))}else if(r==="radio"){n=e('input[name="'+t.attr("name")+'"]:checked').length>0?t.val():"";var s=t.parents("form").first()||t.parents(".control-group").first();s&&(n=s.find("input[name='"+t.attr("name")+"']:checked").map(function(t,n){return e(n).val()}).toArray().join(","))}else n=t.val();return n};e.fn.jqBootstrapValidation=function(t){return n.methods[t]?n.methods[t].apply(this,Array.prototype.slice.call(arguments,1)):typeof t=="object"||!t?n.methods.init.apply(this,arguments):(e.error("Method "+t+" does not exist on jQuery.jqBootstrapValidation"),null)},e.jqBootstrapValidation=function(t){e(":input").not("[type=image],[type=submit]").jqBootstrapValidation.apply(this,arguments)}})(jQuery);
--------------------------------------------------------------------------------
/dist/jqBootstrapValidation.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReactiveRaven/jqBootstrapValidation/96fef5d0800e29cbaf3fa9e2451cce0a1bd0b45d/dist/jqBootstrapValidation.zip
--------------------------------------------------------------------------------
/libs/jquery-loader.js:
--------------------------------------------------------------------------------
1 | (function() {
2 | // Get any jquery=___ param from the query string.
3 | var jqversion = location.search.match(/[?&]jquery=(.*?)(?=&|$)/);
4 | var path;
5 | if (jqversion) {
6 | // A version was specified, load that version from code.jquery.com.
7 | path = 'http://code.jquery.com/jquery-' + jqversion[1] + '.js';
8 | } else {
9 | // No version was specified, load the local version.
10 | path = '../libs/jquery/jquery.js';
11 | }
12 | // This is the only time I'll ever use document.write, I promise!
13 | document.write('');
14 | }());
15 |
--------------------------------------------------------------------------------
/libs/jquery/jquery-migrate.1.2.0.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * jQuery Migrate - v1.2.0 - 2013-05-01
3 | * https://github.com/jquery/jquery-migrate
4 | * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors; Licensed MIT
5 | */
6 | (function( jQuery, window, undefined ) {
7 | // See http://bugs.jquery.com/ticket/13335
8 | // "use strict";
9 |
10 |
11 | var warnedAbout = {};
12 |
13 | // List of warnings already given; public read only
14 | jQuery.migrateWarnings = [];
15 |
16 | // Set to true to prevent console output; migrateWarnings still maintained
17 | // jQuery.migrateMute = false;
18 |
19 | // Show a message on the console so devs know we're active
20 | if ( !jQuery.migrateMute && window.console && window.console.log ) {
21 | window.console.log("JQMIGRATE: Logging is active");
22 | }
23 |
24 | // Set to false to disable traces that appear with warnings
25 | if ( jQuery.migrateTrace === undefined ) {
26 | jQuery.migrateTrace = true;
27 | }
28 |
29 | // Forget any warnings we've already given; public
30 | jQuery.migrateReset = function() {
31 | warnedAbout = {};
32 | jQuery.migrateWarnings.length = 0;
33 | };
34 |
35 | function migrateWarn( msg) {
36 | var console = window.console;
37 | if ( !warnedAbout[ msg ] ) {
38 | warnedAbout[ msg ] = true;
39 | jQuery.migrateWarnings.push( msg );
40 | if ( console && console.warn && !jQuery.migrateMute ) {
41 | console.warn( "JQMIGRATE: " + msg );
42 | if ( jQuery.migrateTrace && console.trace ) {
43 | console.trace();
44 | }
45 | }
46 | }
47 | }
48 |
49 | function migrateWarnProp( obj, prop, value, msg ) {
50 | if ( Object.defineProperty ) {
51 | // On ES5 browsers (non-oldIE), warn if the code tries to get prop;
52 | // allow property to be overwritten in case some other plugin wants it
53 | try {
54 | Object.defineProperty( obj, prop, {
55 | configurable: true,
56 | enumerable: true,
57 | get: function() {
58 | migrateWarn( msg );
59 | return value;
60 | },
61 | set: function( newValue ) {
62 | migrateWarn( msg );
63 | value = newValue;
64 | }
65 | });
66 | return;
67 | } catch( err ) {
68 | // IE8 is a dope about Object.defineProperty, can't warn there
69 | }
70 | }
71 |
72 | // Non-ES5 (or broken) browser; just set the property
73 | jQuery._definePropertyBroken = true;
74 | obj[ prop ] = value;
75 | }
76 |
77 | if ( document.compatMode === "BackCompat" ) {
78 | // jQuery has never supported or tested Quirks Mode
79 | migrateWarn( "jQuery is not compatible with Quirks Mode" );
80 | }
81 |
82 |
83 | var attrFn = jQuery( "", { size: 1 } ).attr("size") && jQuery.attrFn,
84 | oldAttr = jQuery.attr,
85 | valueAttrGet = jQuery.attrHooks.value && jQuery.attrHooks.value.get ||
86 | function() { return null; },
87 | valueAttrSet = jQuery.attrHooks.value && jQuery.attrHooks.value.set ||
88 | function() { return undefined; },
89 | rnoType = /^(?:input|button)$/i,
90 | rnoAttrNodeType = /^[238]$/,
91 | rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
92 | ruseDefault = /^(?:checked|selected)$/i;
93 |
94 | // jQuery.attrFn
95 | migrateWarnProp( jQuery, "attrFn", attrFn || {}, "jQuery.attrFn is deprecated" );
96 |
97 | jQuery.attr = function( elem, name, value, pass ) {
98 | var lowerName = name.toLowerCase(),
99 | nType = elem && elem.nodeType;
100 |
101 | if ( pass ) {
102 | // Since pass is used internally, we only warn for new jQuery
103 | // versions where there isn't a pass arg in the formal params
104 | if ( oldAttr.length < 4 ) {
105 | migrateWarn("jQuery.fn.attr( props, pass ) is deprecated");
106 | }
107 | if ( elem && !rnoAttrNodeType.test( nType ) &&
108 | (attrFn ? name in attrFn : jQuery.isFunction(jQuery.fn[name])) ) {
109 | return jQuery( elem )[ name ]( value );
110 | }
111 | }
112 |
113 | // Warn if user tries to set `type`, since it breaks on IE 6/7/8; by checking
114 | // for disconnected elements we don't warn on $( "