PageSourceSearch

https://www.saybrook.edu/wp-content/plugins/ninja-forms-conditiona…&utm_medium=topnav&utm_campaign=apply

js saybrook.edu collected 2026-09-24 09:10:28 UTC 43,122 bytes, 1,256 lines download raw bytes

vendor: 12,633 bytes, lines 1-348
1(function () {
2/**
3 * @license almond 0.3.1 Copyright (c) 2011-2014, The Dojo Foundation All Rights Reserved.
4 * Available via the MIT or new BSD license.
5 * see: http://github.com/jrburke/almond for details
6 */
7//Going sloppy to avoid 'use strict' string cost, but strict practices should
8//be followed.
9/*jslint sloppy: true */
10/*global setTimeout: false */
11
12var requirejs, require, define;
13(function (undef) {
14    var main, req, makeMap, handlers,
15        defined = {},
16        waiting = {},
17        config = {},
18        defining = {},
19        hasOwn = Object.prototype.hasOwnProperty,
20        aps = [].slice,
21        jsSuffixRegExp = /\.js$/;
22
23    function hasProp(obj, prop) {
24        return hasOwn.call(obj, prop);
25    }
26
27    /**
28     * Given a relative module name, like ./something, normalize it to
29     * a real name that can be mapped to a path.
30     * @param {String} name the relative name
31     * @param {String} baseName a real name that the name arg is relative
32     * to.
33     * @returns {String} normalized name
34     */
35    function normalize(name, baseName) {
36        var nameParts, nameSegment, mapValue, foundMap, lastIndex,
37            foundI, foundStarMap, starI, i, j, part,
38            baseParts = baseName && baseName.split("/"),
39            map = config.map,
40            starMap = (map && map['*']) || {};
41
42        //Adjust any relative paths.
43        if (name && name.charAt(0) === ".") {
44            //If have a base name, try to normalize against it,
45            //otherwise, assume it is a top-level require that will
46            //be relative to baseUrl in the end.
47            if (baseName) {
48                name = name.split('/');
49                lastIndex = name.length - 1;
50
51                // Node .js allowance:
52                if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
53                    name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
54                }
55
56                //Lop off the last part of baseParts, so that . matches the
57                //"directory" and not name of the baseName's module. For instance,
58                //baseName of "one/two/three", maps to "one/two/three.js", but we
59                //want the directory, "one/two" for this normalization.
60                name = baseParts.slice(0, baseParts.length - 1).concat(name);
61
62                //start trimDots
63                for (i = 0; i < name.length; i += 1) {
64                    part = name[i];
65                    if (part === ".") {
66                        name.splice(i, 1);
67                        i -= 1;
68                    } else if (part === "..") {
69                        if (i === 1 && (name[2] === '..' || name[0] === '..')) {
70                            //End of the line. Keep at least one non-dot
71                            //path segment at the front so it can be mapped
72                            //correctly to disk. Otherwise, there is likely
73                            //no path mapping for a path starting with '..'.
74                            //This can still fail, but catches the most reasonable
75                            //uses of ..
76                            break;
77                        } else if (i > 0) {
78                            name.splice(i - 1, 2);
79                            i -= 2;
80                        }
81                    }
82                }
83                //end trimDots
84
85                name = name.join("/");
86            } else if (name.indexOf('./') === 0) {
87                // No baseName, so this is ID is resolved relative
88                // to baseUrl, pull off the leading dot.
89                name = name.substring(2);
90            }
91        }
92
93        //Apply map config if available.
94        if ((baseParts || starMap) && map) {
95            nameParts = name.split('/');
96
97            for (i = nameParts.length; i > 0; i -= 1) {
98                nameSegment = nameParts.slice(0, i).join("/");
99
100                if (baseParts) {
101                    //Find the longest baseName segment match in the config.
102                    //So, do joins on the biggest to smallest lengths of baseParts.
103                    for (j = baseParts.length; j > 0; j -= 1) {
104                        mapValue = map[baseParts.slice(0, j).join('/')];
105
106                        //baseName segment has  config, find if it has one for
107                        //this name.
108                        if (mapValue) {
109                            mapValue = mapValue[nameSegment];
110                            if (mapValue) {
111                                //Match, update name to the new value.
112                                foundMap = mapValue;
113                                foundI = i;
114                                break;
115                            }
116                        }
117                    }
118                }
119
120                if (foundMap) {
121                    break;
122                }
123
124                //Check for a star map match, but just hold on to it,
125                //if there is a shorter segment match later in a matching
126                //config, then favor over this star map.
127                if (!foundStarMap && starMap && starMap[nameSegment]) {
128                    foundStarMap = starMap[nameSegment];
129                    starI = i;
130                }
131            }
132
133            if (!foundMap && foundStarMap) {
134                foundMap = foundStarMap;
135                foundI = starI;
136            }
137
138            if (foundMap) {
139                nameParts.splice(0, foundI, foundMap);
140                name = nameParts.join('/');
141            }
142        }
143
144        return name;
145    }
146
147    function makeRequire(relName, forceSync) {
148        return function () {
149            //A version of a require function that passes a moduleName
150            //value for items that may need to
151            //look up paths relative to the moduleName
152            var args = aps.call(arguments, 0);
153
154            //If first arg is not require('string'), and there is only
155            //one arg, it is the array form without a callback. Insert
156            //a null so that the following concat is correct.
157            if (typeof args[0] !== 'string' && args.length === 1) {
158                args.push(null);
159            }
160            return req.apply(undef, args.concat([relName, forceSync]));
161        };
162    }
163
164    function makeNormalize(relName) {
165        return function (name) {
166            return normalize(name, relName);
167        };
168    }
169
170    function makeLoad(depName) {
171        return function (value) {
172            defined[depName] = value;
173        };
174    }
175
176    function callDep(name) {
177        if (hasProp(waiting, name)) {
178            var args = waiting[name];
179            delete waiting[name];
180            defining[name] = true;
181            main.apply(undef, args);
182        }
183
184        if (!hasProp(defined, name) && !hasProp(defining, name)) {
185            throw new Error('No ' + name);
186        }
187        return defined[name];
188    }
189
190    //Turns a plugin!resource to [plugin, resource]
191    //with the plugin being undefined if the name
192    //did not have a plugin prefix.
193    function splitPrefix(name) {
194        var prefix,
195            index = name ? name.indexOf('!') : -1;
196        if (index > -1) {
197            prefix = name.substring(0, index);
198            name = name.substring(index + 1, name.length);
199        }
200        return [prefix, name];
201    }
202
203    /**
204     * Makes a name map, normalizing the name, and using a plugin
205     * for normalization if necessary. Grabs a ref to plugin
206     * too, as an optimization.
207     */
208    makeMap = function (name, relName) {
209        var plugin,
210            parts = splitPrefix(name),
211            prefix = parts[0];
212
213        name = parts[1];
214
215        if (prefix) {
216            prefix = normalize(prefix, relName);
217            plugin = callDep(prefix);
218        }
219
220        //Normalize according
221        if (prefix) {
222            if (plugin && plugin.normalize) {
223                name = plugin.normalize(name, makeNormalize(relName));
224            } else {
225                name = normalize(name, relName);
226            }
227        } else {
228            name = normalize(name, relName);
229            parts = splitPrefix(name);
230            prefix = parts[0];
231            name = parts[1];
232            if (prefix) {
233                plugin = callDep(prefix);
234            }
235        }
236
237        //Using ridiculous property names for space reasons
238        return {
239            f: prefix ? prefix + '!' + name : name, //fullName
240            n: name,
241            pr: prefix,
242            p: plugin
243        };
244    };
245
246    function makeConfig(name) {
247        return function () {
248            return (config && config.config && config.config[name]) || {};
249        };
250    }
251
252    handlers = {
253        require: function (name) {
254            return makeRequire(name);
255        },
256        exports: function (name) {
257            var e = defined[name];
258            if (typeof e !== 'undefined') {
259                return e;
260            } else {
261                return (defined[name] = {});
262            }
263        },
264        module: function (name) {
265            return {
266                id: name,
267                uri: '',
268                exports: defined[name],
269                config: makeConfig(name)
270            };
271        }
272    };
273
274    main = function (name, deps, callback, relName) {
275        var cjsModule, depName, ret, map, i,
276            args = [],
277            callbackType = typeof callback,
278            usingExports;
279
280        //Use name if no relName
281        relName = relName || name;
282
283        //Call the callback to define the module, if necessary.
284        if (callbackType === 'undefined' || callbackType === 'function') {
285            //Pull out the defined dependencies and pass the ordered
286            //values to the callback.
287            //Default to [require, exports, module] if no deps
288            deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps;
289            for (i = 0; i < deps.length; i += 1) {
290                map = makeMap(deps[i], relName);
291                depName = map.f;
292
293                //Fast path CommonJS standard dependencies.
294                if (depName === "require") {
295                    args[i] = handlers.require(name);
296                } else if (depName === "exports") {
297                    //CommonJS module spec 1.1
298                    args[i] = handlers.exports(name);
299                    usingExports = true;
300                } else if (depName === "module") {
301                    //CommonJS module spec 1.1
302                    cjsModule = args[i] = handlers.module(name);
303                } else if (hasProp(defined, depName) ||
304                           hasProp(waiting, depName) ||
305                           hasProp(defining, depName)) {
306                    args[i] = callDep(depName);
307                } else if (map.p) {
308                    map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {});
309                    args[i] = defined[depName];
310                } else {
311                    throw new Error(name + ' missing ' + depName);
312                }
313            }
314
315            ret = callback ? callback.apply(defined[name], args) : undefined;
316
317            if (name) {
318                //If setting exports via "module" is in play,
319                //favor that over return value and exports. After that,
320                //favor a non-undefined return value over exports use.
321                if (cjsModule && cjsModule.exports !== undef &&
322                        cjsModule.exports !== defined[name]) {
323                    defined[name] = cjsModule.exports;
324                } else if (ret !== undef || !usingExports) {
325                    //Use the return value from the function.
326                    defined[name] = ret;
327                }
328            }
329        } else if (name) {
330            //May just be an object definition for the module. Only
331            //worry about defining if have a module name.
332            defined[name] = callback;
333        }
334    };
335
336    requirejs = require = req = function (deps, callback, relName, forceSync, alt) {
337        if (typeof deps === "string") {
338            if (handlers[deps]) {
339                //callback in this case is really relName
340                return handlers[deps](callback);
341            }
342            //Just return the module wanted. In this scenario, the
343            //deps arg is the module name, and second arg (if passed)
344            //is just the relName.
345            //Normalize module name, if it contains . or ..
346            return callDep(makeMap(deps, callback).f);
347        } else if (!deps.splice) {
348            //deps is a config object, not an array.
349            config = deps;
350            if (config.deps) {
351                req(config.deps, config.callback);
352            }
353            if (!callback) {
354                return;
355            }
356
357            if (callback.splice) {
358                //callback is an array, which means it is a dependency list.
359                //Adjust args if there are dependencies
360                deps = callback;
361                callback = relName;
362                relName = null;
363            } else {
364                deps = undef;
365            }
366        }
367
368        //Support require(['a'])
369        callback = callback || function () {};
370
371        //If relName is a function, it is an errback handler,
372        //so remove it.
373        if (typeof relName === 'function') {
374            relName = forceSync;
375            forceSync = alt;
376        }
377
378        //Simulate async callback;
379        if (forceSync) {
380            main(undef, deps, callback, relName);
381        } else {
382            //Using a non-zero value because of concern for what old browsers
383            //do, and latest browsers "upgrade" to 4 if lower value is used:
384            //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout:
385            //If want a value immediately, use require('id') instead -- something
386            //that works in almond on the global level, but not guaranteed and
387            //unlikely to work in other AMD implementations.
388            setTimeout(function () {
389                main(undef, deps, callback, relName);
390            }, 4);
391        }
392
393        return req;
394    };
395
396    /**
397     * Just drops the config on the floor, but returns req in case
398     * the config return value is used.
399     */
400    req.config = function (cfg) {
401        return req(cfg);
402    };
403
404    /**
405     * Expose module registry for debugging and tooling
406     */
407    requirejs._defined = defined;
408
409    define = function (name, deps, callback) {
410        if (typeof name !== 'string') {
411            throw new Error('See almond README: incorrect module build, no module name');
412        }
413
414        //This module may not have dependencies
415        if (!deps.splice) {
416            //deps is not an array, so probably means
417            //an object literal or factory function for
418            //the value. Adjust args.
419            callback = deps;
420            deps = [];
421        }
422
423        if (!hasProp(defined, name) && !hasProp(waiting, name)) {
424            waiting[name] = [name, deps, callback];
425        }
426    };
427
428    define.amd = {
429        jQuery: true
430    };
431}());
432
433define("../lib/almond", function(){});
434
435define( 'models/whenModel',[], function() {
436	var model = Backbone.Model.extend( {
437		initialize: function( models, options ) {
438			/*
439			 * If our key or comparator is empty, don't do anything else.
440			 */
441			if ( ! this.get( 'key' ) || ! this.get( 'comparator' ) ) return;
442
443			/*
444			 * Our key could be a field or a calc.
445			 * We need to setup a listener on either the field or calc model for changes.
446			 */
447			if ( 'calc' == this.get( 'type' ) ) { // We have a calculation key
448				/*
449				 * Get our calc model
450				 */
451				var calcModel = nfRadio.channel( 'form-' + this.collection.options.condition.collection.formModel.get( 'id' ) ).request( 'get:calc', this.get( 'key' ) );
452
453				if( 'undefined' == typeof calcModel ) return;
454
455				/*
456				 * When we update our calculation, update our compare
457				 */
458				this.listenTo( calcModel, 'change:value', this.updateCalcCompare );
459				/*
460				 * Update our compare status.
461				 */
462				this.updateCalcCompare( calcModel );
463			} else { // We have a field key
464				// Get our field model
465				var fieldModel = nfRadio.channel( 'form-' + options.condition.collection.formModel.get( 'id' ) ).request( 'get:fieldByKey', this.get( 'key' ) );
466
467				if( 'undefined' == typeof fieldModel ) return;
468
469				// When we change the value of our field, update our compare status.
470				fieldModel.on( 'change:value', this.updateFieldCompare, this );
471				// When we keyup in our field, maybe update our compare status.
472				this.listenTo( nfRadio.channel( 'field-' + fieldModel.get( 'id' ) ), 'keyup:field', this.maybeupdateFieldCompare );
473				// Update our compare status.
474				this.updateFieldCompare( fieldModel );
475
476				/*
477				 * TODO: This should be moved to the show_field/hide_field file because it is specific to showing and hiding.
478				 * Create a radio message here so that the specific JS file can hook into whenModel init.
479				 */
480				fieldModel.on( 'change:visible', this.updateFieldCompare, this );
481			}
482		},
483
484		updateCalcCompare: function( calcModel ) {
485			this.updateCompare( calcModel.get( 'value' ) );
486		},
487
488		maybeupdateFieldCompare: function( el, fieldModel, keyCode ) {
489			if( 'checkbox' == fieldModel.get( 'type' ) ){
490                var fieldValue = ( 'checked' == jQuery( el ).attr( 'checked' ) ) ? 1 : 0;
491            } else if( 'listcheckbox' == fieldModel.get( 'type' ) ) {
492				// This field isn't a single element, so we need to reference the fieldModel, instead of the DOM.
493                var fieldValue = fieldModel.get( 'value' ).join();
494            } else if ( 'listradio' == fieldModel.get( 'type' ) ) {
495				/*
496				 * Use the field model's actual selected value rather than jQuery(el).val().
497				 * jQuery(el).val() returns the value attribute of whichever radio button has
498				 * focus, even if it has not been selected by the user. When tabbing into a
499				 * radio field, the keyup event fires on the focused (but unselected) radio
500				 * button, causing jQuery(el).val() to return that option's value and
501				 * incorrectly trigger conditions. The field model value only reflects a
502				 * genuinely selected option.
503				 */
504				var fieldValue = fieldModel.get( 'value' );
505            } else if ( 'date' == fieldModel.get ('type' ) ) {
506				var fieldValue = fieldModel.get( 'value' );
507
508				if ( _.isEmpty( fieldValue ) ) {
509					if ( 1 == fieldModel.get( 'date_default' ) ) {
510						var now = new Date();
511						fieldValue = now.getFullYear() + '/' + ( '0' + ( now.getMonth() + 1 ) ).slice( -2 ) + '/' + ( '0' + now.getDate() ).slice( -2 );
512					} else {
513						fieldValue = '1970/01/01';
514					}
515				}
516
517				let date_mode = fieldModel.get( 'date_mode' );
518				if ( 'undefined' == typeof date_mode ) { // If 'date_mode' is undefined, then we assume it's date_only.
519					date_mode = 'date_only';
520				}
521				let date = 0;
522				// If we're in time_only mode, then we need to use 1970-01-01 as our date.
523				if ( 'time_only' == fieldModel.get( 'date_mode' ) ) {
524					date = '1970/01/01';
525				} else {
526					date = fieldValue;
527				}
528
529				// Convert field value into a timestamp
530				let hour = fieldModel.get( 'selected_hour' );
531				if ( 'undefined' == typeof hour ) {
532					hour = '00';
533				}
534
535				let minute = fieldModel.get( 'selected_minute' );
536				if ( 'undefined' == typeof minute ) {
537					minute = '00';
538				}
539
540				// If we have a date_and_time field, but we haven't selected a date yet, we don't need to compare.
541				if ( 'date_and_time' == date_mode && '1970/01/01' == date ) {
542					fieldValue = false;
543				} else {
544					fieldValue = date + ' ' + hour + ':' + minute + ' UT';
545
546					let dateObject = new Date( fieldValue );
547					fieldValue = Math.floor( dateObject.getTime() / 1000 );					
548				}
549			} else {
550				var fieldValue = jQuery( el ).val();
551			}
552
553			this.updateFieldCompare( fieldModel, null, fieldValue );
554		},
555
556		updateCompare: function( value ) {
557			var this_val = this.get( 'value' );
558
559			// if this is a calcModel then let's convert to number for comparison
560			if ( 'calc' === this.get( 'type' ) ) {
561				this_val = Number( this_val );
562				value = Number( value );
563			}
564			// Check to see if the value of the field model value COMPARATOR the value of our when condition is true.
565			var status = this.compareValues[ this.get( 'comparator' ) ]( value, this_val );
566			this.set( 'status', status );
567		},
568
569		updateFieldCompare: function( fieldModel, val, fieldValue ) {
570			if ( _.isEmpty( fieldValue ) ) {
571				fieldValue = fieldModel.get( 'value' );
572			}
573
574			// Change the value of checkboxes to match the new convention.
575			if( 'checkbox' == fieldModel.get( 'type' ) ) {
576				if( 0 == fieldValue ) {
577					fieldValue = 'unchecked';
578				} else {
579					fieldValue = 'checked';
580				}
581			} else if ( 'date' == fieldModel.get( 'type' ) ) {
582				if ( _.isEmpty( fieldValue ) ) {
583					if ( 1 == fieldModel.get( 'date_default' ) ) {
584						var now = new Date();
585						fieldValue = now.getFullYear() + '/' + ( '0' + ( now.getMonth() + 1 ) ).slice( -2 ) + '/' + ( '0' + now.getDate() ).slice( -2 );
586					} else {
587						fieldValue = '1970/01/01';
588					}
589				}
590
591				let date_mode = fieldModel.get( 'date_mode' );
592				if ( 'undefined' == typeof date_mode ) { // If 'date_mode' is undefined, then we assume it's date_only.
593					date_mode = 'date_only';
594				}
595				let date = 0;
596				// If we're in time_only mode, then we need to use 1970-01-01 as our date.
597				if ( 'time_only' == fieldModel.get( 'date_mode' ) ) {
598					date = '1970/01/01';
599				} else {
600					date = fieldValue;
601				}
602
603				// Convert field value into a timestamp
604				let hour = fieldModel.get( 'selected_hour' );
605				if ( 'undefined' == typeof hour ) {
606					hour = '00';
607				}
608
609				let ampm = fieldModel.get( 'selected_ampm' );
610				if ( 'undefined' != typeof ampm ) {
611					// Convert our hour into 24 hr format.
612					if ( 'pm' == ampm && '12' != hour ) {
613						hour = parseInt( hour ) + 12;
614					} else if ( 'am' == ampm && '12' == hour ) {
615						hour = '00';
616					}
617				}
618
619				let minute = fieldModel.get( 'selected_minute' );
620				if ( 'undefined' == typeof minute ) {
621					minute = '00';
622				}
623
624				// If we have a date_and_time field, but we haven't selected a date yet, we don't need to compare.
625				if ( 'date_and_time' == date_mode && '1970/01/01' == date ) {
626					fieldValue = false;
627				} else {
628					fieldValue = date + ' ' + hour + ':' + minute + ' UT';
629
630					let dateObject = new Date( fieldValue );
631					fieldValue = Math.floor( dateObject.getTime() / 1000 );					
632				}
633			}
634
635			this.updateCompare( fieldValue );
636
637			/*
638			 * TODO: This should be moved to the show_field/hide_field file because it is specific to showing and hiding.
639			 */
640			if ( ! fieldModel.get( 'visible' ) ) {
641				this.set( 'status', false );
642			}			
643		},
644
645		compareValues: {
646			'equal': function( a, b ) {
647				return a == b;
648			},
649			'notequal': function( a, b ) {
650				return a != b;
651			},
652			'contains': function( a, b ) {
653				if ( jQuery.isArray( a ) ) {
654					/*
655					 * If a is an array, then we're searching for an index.
656					 */
657					return a.indexOf( b ) >= 0;
658				} else {
659					/*
660					 * If a is a string, then we're searching for a string position.
661					 *
662					 * If our b value has quotes in it, we want to find that exact word or phrase.
663					 */
664					if ( b.indexOf( '"' ) >= 0 ) {
665						b = b.replace( /['"]+/g, '' );
666						return new RegExp("\\b" + b + "\\b").test( a );
667					}
668					return a.toLowerCase().indexOf( b.toLowerCase() ) >= 0; 				
669				}
670			},
671			'notcontains': function( a, b ) {
672				return ! this.contains( a, b );
673			},
674			'greater': function( a, b ) {
675				/*
676				 * In 2.9.x, you could use the greater and less like string count.
677				 * i.e. if textbox > (empty string) do something.
678				 * This recreates that ability.
679				 */
680				if ( jQuery.isNumeric( b ) ) {
681					return parseFloat( a ) > parseFloat( b );
682				} else if ( 'string' == typeof a ) {
683					return 0 < a.length;
684				}
685				
686			},
687			'less': function( a, b ) {
688				/*
689				 * In 2.9.x, you could use the greater and less like string count.
690				 * i.e. if textbox > (empty string) do something.
691				 * This recreates that ability.
692				 */
693				if ( jQuery.isNumeric( b ) ) {
694					return parseFloat( a ) < parseFloat( b );
695				} else if ( 'string' == typeof a ) {
696					return 0 >= a.length;
697				}
698		
699			},
700			'greaterequal': function( a, b ) {
701				return parseFloat( a ) > parseFloat( b ) || parseFloat( a ) == parseFloat( b );
702			},
703			'lessequal': function( a, b ) {
704				return parseFloat( a ) < parseFloat( b ) || parseFloat( a ) == parseFloat( b );
705			}
706		} 
707	} );
708	
709	return model;
710} );
711define( 'models/whenCollection',['models/whenModel'], function( WhenModel ) {
712	var collection = Backbone.Collection.extend( {
713		model: WhenModel,
714
715		initialize: function( models, options ) {
716			this.options = options;
717		}
718	} );
719	return collection;
720} );
721define( 'models/conditionModel',[ 'models/whenCollection' ], function( WhenCollection ) {
722	var model = Backbone.Model.extend( {
723		initialize: function( options ) {
724			/*
725			 * Our "when" statement will be like:
726			 * When field1 == value
727			 * AND field2 == value
728			 *
729			 * We need to create a collection out of this when statement, with each row as a model.
730			 */
731			this.set( 'when', new WhenCollection( this.get( 'when' ), { condition: this } ) );
732			/*
733			 * When we update any of our "when" models' status, check to see if we should send a message.
734			 */
735			this.get( 'when' ).on( 'change:status', this.checkWhen, this );
736			/*
737			 * Check our initial status;
738			 * Deferred via setTimeout to allow all field relationships (e.g. Confirm field pairings)
739			 * to be fully established before conditions first evaluate on page load.
740			 */
741			setTimeout( function() {
742				this.checkWhen();
743			}.bind( this ), 0 );
744		},
745
746		checkWhen: function() {
747			/*
748			 * If we have any OR connectors, then any status being true should trigger pass.
749			 * Otherwise, we need every status to be true.
750			 */
751			var statusResults = this.get( 'when' ).pluck( 'status' );
752
753			var connectors = this.get( 'when' ).pluck( 'connector' );
754			var allAND = _.every( _.values( connectors ), function( v ) { return v == 'AND' }, this );
755			if ( allAND ) {
756				var status = _.every( _.values( statusResults ), function(v) { return v; }, this );
757			} else {
758				var status = _.some( _.values( statusResults ), function(v) { return v; }, this );
759			}
760
761			if ( status ) {
762			   	/*
763			 	 * Send out a request for each of our "then" statements.
764			 	 */
765				_.each( this.get( 'then' ), function( then, index ) {
766					nfRadio.channel( 'condition:trigger' ).request( then.trigger, this, then );
767				}, this );
768			} else {
769				/*
770				 * Send out a request for each of our "else" statements.
771				 */
772				_.each( this.get( 'else' ), function( elseData, index ) {
773					nfRadio.channel( 'condition:trigger' ).request( elseData.trigger, this, elseData );
774				}, this );
775			}
776		}
777	} );
778
779	return model;
780} );
781
782define( 'models/conditionCollection',['models/conditionModel'], function( ConditionModel ) {
783	var collection = Backbone.Collection.extend( {
784		model: ConditionModel,
785
786		initialize: function( models, options ) {
787			this.formModel = options.formModel;
788		}
789	} );
790	return collection;
791} );
792/**
793 * Initialise condition collection
794 * 
795 * @package Ninja Forms Conditional Logic
796 * @copyright (c) 2016 WP Ninjas
797 * @since 3.0
798 */
799define( 'controllers/initCollection',[ 'models/conditionCollection' ], function( ConditionCollection ) {
800	var controller = Marionette.Object.extend( {
801		initialize: function( formModel ) {
802			this.collection = new ConditionCollection( formModel.get( 'conditions' ), { formModel: formModel } );
803            this.listenTo(nfRadio.channel('fields'), 'reset:collection', this.resetCollection);
804		},
805        resetCollection: function( fieldsCollection ) {
806            var formModel = fieldsCollection.options.formModel;
807            this.collection = new ConditionCollection( formModel.get( 'conditions' ), { formModel: formModel } );
808        }
809	});
810
811	return controller;
812} );
813/**
814 * Handle showing/hiding fields
815 * 
816 * @package Ninja Forms Conditional Logic
817 * @copyright (c) 2016 WP Ninjas
818 * @since 3.0
819 */
820define( 'controllers/showHide',[], function() {
821	var controller = Marionette.Object.extend( {
822		initialize: function() {
823			nfRadio.channel( 'condition:trigger' ).reply( 'hide_field', this.hideField, this );
824			nfRadio.channel( 'condition:trigger' ).reply( 'show_field', this.show
824Field, this );
825		},
826
827		hideField: function( conditionModel, then ) {
828			var formId = conditionModel.collection.formModel.get( 'id' );
829			var targetFieldModel = nfRadio.channel( 'form-' + formId ).request( 'get:fieldByKey', then.key );
830
831			if( 'undefined' == typeof targetFieldModel ) return;
832			targetFieldModel.set( 'visible', false );
833            if ( ! targetFieldModel.get( 'clean' ) ) {
834				targetFieldModel.trigger( 'change:value', targetFieldModel );
835			}
836
837			nfRadio.channel( 'fields' ).request( 'remove:error', targetFieldModel.get( 'id' ), 'required-error' );
838
839			// For repeater fields, mark child field models as not visible so JS
840			// validation skips their required check on submission.
841			if ( 'repeater' === targetFieldModel.get( 'type' ) ) {
842				this.setRepeaterChildrenVisible( targetFieldModel, false );
843			}
844		},
845
846		/**
847		 * Set the visible state on all child field models of a Repeater field.
848		 *
849		 * Child models live inside the Repeater's own sets collection, not in the
850		 * top-level form field collection. When visible is false, NF core's
851		 * validateModelData skips required validation for those fields.
852		 */
853		setRepeaterChildrenVisible: function( repeaterModel, visible ) {
854			var sets = repeaterModel.get( 'sets' );
855			if ( ! sets ) return;
856
857			sets.each( function( set ) {
858				var fields = set.get( 'fields' );
859				if ( ! fields ) return;
860
861				fields.each( function( fieldModel ) {
862					fieldModel.set( 'visible', visible );
863					if ( ! visible ) {
864						nfRadio.channel( 'fields' ).request( 'remove:error', fieldModel.get( 'id' ), 'required-error' );
865					}
866				} );
867			} );
868		},
869
870		showField: function( conditionModel, then ) {
871			var targetFieldModel = nfRadio.channel( 'form-' + conditionModel.collection.formModel.get( 'id' ) ).request( 'get:fieldByKey', then.key );
872			//TODO: Add an error to let the user know the show/hide field is empty.
873			if( 'undefined' == typeof targetFieldModel ) return;
874			targetFieldModel.set( 'visible', true );
875            if ( ! targetFieldModel.get( 'clean' ) ) {
876                targetFieldModel.trigger( 'change:value', targetFieldModel );
877			}
878			// For repeater fields, restore child field models to visible so
879			// required validation applies again when the Repeater is shown.
880			if ( 'repeater' === targetFieldModel.get( 'type' ) ) {
881				this.setRepeaterChildrenVisible( targetFieldModel, true );
882			}
883			if ( 'recaptcha' === targetFieldModel.get( 'type' ) ) {
884				this.renderRecaptcha();
885			}
886			if ( 'turnstile' === targetFieldModel.get( 'type' ) ) {
887				this.renderTurnstile();
888			}
889			var viewEl = { el: nfRadio.channel( 'form-' + conditionModel.collection.formModel.get( 'id' ) ).request( 'get:el' ) };
890            nfRadio.channel( 'form' ).request( 'init:help', viewEl );
891		},
892
893		renderRecaptcha: function() {
894			jQuery( '.g-recaptcha' ).each( function() {
895                var callback = jQuery( this ).data( 'callback' );
896                var fieldID = jQuery( this ).data( 'fieldid' );
897                if ( typeof window[ callback ] !== 'function' ){
898                    window[ callback ] = function( response ) {
899                        nfRadio.channel( 'recaptcha' ).request( 'update:response', response, fieldID );
900                    };
901                }
902				var opts = {
903					theme: jQuery( this ).data( 'theme' ),
904					sitekey: jQuery( this ).data( 'sitekey' ),
905					callback: callback
906				};
907				
908				grecaptcha.render( jQuery( this )[0], opts );
909			} );
910		},
911
912		renderTurnstile: function() {
913			// Ensure turnstile API is loaded
914			if ( typeof turnstile === 'undefined' ) {
915				return;
916			}
917
918			jQuery( '.cf-turnstile, .nf-cf-turnstile' ).each( function() {
919				var element = this;
920				var sitekey = jQuery( element ).data( 'sitekey' );
921				var fieldID = jQuery( element ).data( 'fieldid' );
922				
923				// Skip if no sitekey or already rendered
924				if ( ! sitekey || jQuery( element ).children().length > 0 ) {
925					return;
926				}
927
928				try {
929					// Create callback function for this specific field
930					var callbackName = 'nfTurnstileCallback_' + fieldID;
931					
932					// Define the callback function
933					window[ callbackName ] = function( token ) {
934						// Update the hidden input field
935						var input = document.getElementById( 'nf-field-' + fieldID );
936						if ( input ) {
937							input.value = token;
938							jQuery( input ).trigger( 'change' );
939							
940							// Remove error states
941							jQuery( input ).closest( '.field-wrap' ).removeClass( 'nf-error' );
942							jQuery( input ).closest( '.field-wrap' ).find( '.nf-error-msg' ).remove();
943						}
944
945						// Update via radio channel if available
946						if ( typeof nfRadio !== 'undefined' && nfRadio.channel ) {
947							try {
948								nfRadio.channel( 'turnstile' ).request( 'update:response', token, fieldID );
949							} catch( e ) {
950								// Silent fail
951							}
952						}
953					};
954
955					// Render the turnstile widget
956					turnstile.render( element, {
957						sitekey: sitekey,
958						theme: jQuery( element ).data( 'theme' ) || 'auto',
959						size: jQuery( element ).data( 'size' ) || 'normal',
960						callback: callbackName
961					} );
962					
963				} catch( e ) {
964					// Silent fail for turnstile render errors
965				}
966			} );
967		}
968	});
969
970	return controller;
971} );
972/**
973 * Setting/unsetting required.
974 * 
975 * @package Ninja Forms Conditional Logic
976 * @copyright (c) 2019 WP Ninjas
977 * @since 3.0
978 */
979define( 'controllers/changeRequired',[], function() {
980	var controller = Marionette.Object.extend( {
981		initialize: function() {
982			nfRadio.channel( 'condition:trigger' ).reply( 'set_required', this.setRequired, this );
983			nfRadio.channel( 'condition:trigger' ).reply( 'unset_required', this.unsetRequired, this );
984		},
985
986		setRequired: function( conditionModel, then ) {
987			var targetFieldModel = nfRadio.channel( 'form-' + conditionModel.collection.formModel.get( 'id' ) ).request( 'get:fieldByKey', then.key );
988
989			if( 'undefined' == typeof targetFieldModel ) return;
990            targetFieldModel.set( 'required', 1 );
991			targetFieldModel.trigger( 'reRender', targetFieldModel );
992		},
993
994		unsetRequired: function( conditionModel, then ) {
995			var targetFieldModel = nfRadio.channel( 'form-' + conditionModel.collection.formModel.get( 'id' ) ).request( 'get:fieldByKey', then.key );
996
997			if( 'undefined' == typeof targetFieldModel ) return;
998            targetFieldModel.set( 'required', 0 );
999            targetFieldModel.trigger( 'reRender', targetFieldModel );
1000            // Ensure we resolve any errors when the field is no longer required.
1001			nfRadio.channel( 'fields' ).request( 'remove:error', targetFieldModel.get( 'id' ), 'required-error' );
1002        }
1003        
1004	});
1005
1006	return controller;
1007} );
1008/**
1009 * Handle adding or removing an option from our list
1010 * 
1011 * @package Ninja Forms Conditional Logic
1012 * @copyright (c) 2016 WP Ninjas
1013 * @since 3.0
1014 */
1015define( 'controllers/showHideOption',[], function() {
1016	var controller = Marionette.Object.extend( {
1017		initialize: function() {
1018			nfRadio.channel( 'condition:trigger' ).reply( 'show_option', this.showOption, this );
1019
1020			nfRadio.channel( 'condition:trigger' ).reply( 'hide_option', this.hideOption, this );
1021		},
1022
1023		showOption: function( conditionModel, then ) {
1024			var option = this.getOption( conditionModel, then );
1025			option.visible = true;
1026			this.updateFieldModel( conditionModel, then );
1027		},
1028
1029		hideOption: function( conditionModel, then ) {
1030			var option = this.getOption( conditionModel, then );
1031			option.visible = false;
1032			this.updateFieldModel( conditionModel, then );
1033		},
1034
1035		getFieldModel: function( conditionModel, then ) {
1036			return nfRadio.channel( 'form-' + conditionModel.collection.formModel.get( 'id' ) ).request( 'get:fieldByKey', then.key );
1037		},
1038
1039		getOption: function( conditionModel, then ) {
1040			var targetFieldModel = this.getFieldModel( conditionModel, then );
1041			var options = targetFieldModel.get( 'options' );
1042			return _.find( options, function( option ) { return option.value == then.value } );
1043		},
1044
1045		updateFieldModel: function( conditionModel, then ) {
1046			var targetFieldModel = this.getFieldModel( conditionModel, then );
1047			var options = targetFieldModel.get( 'options' );
1048			targetFieldModel.set( 'options', options );
1049			targetFieldModel.trigger( 'reRender' );
1050		}
1051	});
1052
1053	return controller;
1054} );
1055/**
1056 * Handle changing a field's value
1057 * 
1058 * @package Ninja Forms Conditional Logic
1059 * @copyright (c) 2016 WP Ninjas
1060 * @since 3.0
1061 */
1062define( 'controllers/changeValue',[], function() {
1063	var controller = Marionette.Object.extend( {
1064		initialize: function() {
1065			nfRadio.channel( 'condition:trigger' ).reply( 'change_value', this.changeValue, this );
1066		},
1067
1068		changeValue: function( conditionModel, then ) {
1069			var targetFieldModel = nfRadio.channel( 'form-' + conditionModel.collection.formModel.get( 'id' ) ).request( 'get:fieldByKey', then.key );
1070			/*
1071			 * If we have a checkbox then we need to change the value that is set
1072			 * of the then variable to a 1 or 0 to re-render on the front end when
1073			 * the condition is met.
1074			 */
1075			if( 'checkbox' == targetFieldModel.get( 'type' ) ) {
1076				// We also need to do the opposite of the value that is in the changed model.
1077				if( 'unchecked' == targetFieldModel.changed.value ) {
1078					then.value = 1;
1079                } else if( 'checked' == targetFieldModel ) {
1080					then.value = 0;
1081				}
1082			}
1083            /*
1084             * Change the value of our field model, and then trigger a re-render of its view.
1085             */
1086			targetFieldModel.set( 'value', then.value );
1087			targetFieldModel.trigger( 'reRender', targetFieldModel );
1088		},
1089
1090	});
1091	return controller;
1092} );
1093/**
1094 * Handle selecting/deselecting list options
1095 * 
1096 * @package Ninja Forms Conditional Logic
1097 * @copyright (c) 2016 WP Ninjas
1098 * @since 3.0
1099 */
1100define( 'controllers/selectDeselect',[], function() {
1101	var controller = Marionette.Object.extend( {
1102		initialize: function() {
1103			nfRadio.channel( 'condition:trigger' ).reply( 'select_option', this.selectOption, this );
1104
1105			nfRadio.channel( 'condition:trigger' ).reply( 'deselect_option', this.deselectOption, this );
1106		},
1107
1108		selectOption: function( conditionModel, then ) {
1109			/*
1110			 * Get our field model and set this option's "selected" property to 1
1111			 */
1112			var targetFieldModel = nfRadio.channel( 'form-' + conditionModel.collection.formModel.get( 'id' ) ).request( 'get:fieldByKey', then.key );
1113
1114
1115			if( _.contains( [ 'listselect', 'listcountry', 'liststate' ], targetFieldModel.get( 'type' ) ) ) { // TODO: Make this more dynamic.
1116				targetFieldModel.set('clean', false); // Allows for changes to default values.
1117			}
1118
1119			var options = targetFieldModel.get( 'options' );
1120
1121			var option = _.find( options, { value: then.value } );
1122			option.selected = 1;
1123
1124			targetFieldModel.set( 'options', options );
1125
1126			if( _.contains( [ 'listselect', 'listcountry', 'liststate' ], targetFieldModel.get( 'type' ) ) ) { // TODO: Make this more dynamic.
1127				targetFieldModel.set( 'value', option.value ); // Propagate the selected option to the model's value.
1128			} else {
1129				var value = targetFieldModel.get( 'value' );
1130				if ( _.isArray( value ) ) {
1131                    if ( 0 > value.indexOf( option.value ) ) {
1132                        value.push( option.value );
1133                        // Set the value to nothing so it knows that something has changed.
1134                        targetFieldModel.set( 'value', '' );
1135                    }
1136				} else {
1137					value = option.value;
1138				}
1139				
1140				targetFieldModel.set( 'value', value ); // Propagate the selected option to the model's value.
1141			}
1142
1143			/*
1144			 * Re render our field
1145			 */
1146			targetFieldModel.trigger( 'reRender', targetFieldModel );
1147		},
1148
1149		deselectOption: function( conditionModel, then ) {
1150			/*
1151			 * When we are trying to deselect our option, we need to change it's "selected" property to 0 AND change its value.
1152			 */
1153			var targetFieldModel = nfRadio.channel( 'form-' + conditionModel.collection.formModel.get( 'id' ) ).request( 'get:fieldByKey', then.key );
1154
1155			/*
1156			 * Set "selected" to 0.
1157			 */
1158			var options = targetFieldModel.get( 'options' );
1159			var option = _.find( options, { value: then.value } );
1160			option.selected = 0;
1161			targetFieldModel.set( 'options', options );
1162
1163			/*
1164			 * Update our value
1165			 */
1166			var currentValue = targetFieldModel.get( 'value' );
1167			if ( _.isArray( currentValue ) ) {
1168				currentValue = _.without( currentValue, then.value );
1169			} else {
1170				currentValue = '';
1171			}
1172			targetFieldModel.set( 'value', currentValue );
1173
1174			/*
1175			 * Re render our field
1176			 */
1177			targetFieldModel.trigger( 'reRender', targetFieldModel );
1178		},
1179
1180	});
1181
1182	return controller;
1183} );
1184/**
1185 * Keep an internal record for which actions are active and deactive.
1186 * 
1187 * @package Ninja Forms Conditional Logic
1188 * @copyright (c) 2016 WP Ninjas
1189 * @since 3.0
1190 */
1191define( 'controllers/actions',[], function() {
1192	var controller = Marionette.Object.extend( {
1193		actions: {},
1194		
1195		initialize: function() {
1196			/*
1197			 * Listen for activate/deactivate action messages.
1198			 */
1199			nfRadio.channel( 'condition:trigger' ).reply( 'activate_action', this.activateAction, this );
1200			nfRadio.channel( 'condition:trigger' ).reply( 'deactivate_action', this.deactivateAction, this );
1201		
1202			/*
1203			 * Reply to requests for action status.
1204			 */
1205			nfRadio.channel( 'actions' ).reply( 'get:status', this.getStatus, this );
1206		},
1207
1208		activateAction: function( conditionModel, thenObject ) {
1209			this.actions[ thenObject.key ] = true;
1210			console.log( 'activate action' );
1211		},
1212
1213		deactivateAction: function( conditionModel, thenObject ) {
1214			console.log( 'deactivate action' );
1215			this.actions[ thenObject.key ] = false;
1216		},
1217
1218		getStatus: function( $id ) {
1219			return this.actions[ $id ];
1220		}
1221	});
1222
1223	return controller;
1224} );
1225var nfRadio = Backbone.Radio;
1226
1227require( [ 'controllers/initCollection', 'controllers/showHide', 'controllers/changeRequired', 'controllers/showHideOption', 'controllers/changeValue', 'controllers/selectDeselect', 'controllers/actions' ], function( InitCollection, ShowHide, ChangeRequired, ShowHideOption, ChangeValue, SelectDeselect, Actions ) {
1228
1229	var NFConditionalLogic = Marionette.Application.extend( {
1230
1231		initialize: function( options ) {
1232			this.listenTo( nfRadio.channel( 'form' ), 'after:loaded', this.loadControllers );
1233		},
1234
1235		loadControllers: function( formModel ) {
1236			new ShowHide();
1237			new ChangeRequired();
1238			new ShowHideOption();
1239			new ChangeValue();
1240			new SelectDeselect();
1241			new Actions();
1242			new InitCollection( formModel );
1243		},
1244
1245		onStart: function() {
1246			
1247		}
1248	} );
1249
1250	var nfConditionalLogic = new NFConditionalLogic();
1251	nfConditionalLogic.start();
1252} );
1253define("main", function(){});
1254
1255}());
1256//# sourceMappingURL=front-end.js.map

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.