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 // For date_and_time fields, picking the hour/minute/am-pm only updates 472 // those attributes (not 'value') until the form is actually submitted 473 // (see NF core changeDate.js: changeHoursMinutes). Without these listeners, 474 // the comparison stays frozen at whatever time was selected (usually 00:00) 475 // when the date was first picked, and never re-evaluates as the visitor 476 // picks a time. 477 fieldModel.on( 'change:selected_hour change:selected_minute change:selected_ampm', this.updateFieldCompare, this ); 478 // When we keyup in our field, maybe update our compare status. 479 this.listenTo( nfRadio.channel( 'field-' + fieldModel.get( 'id' ) ), 'keyup:field', this.maybeupdateFieldCompare ); 480 // Update our compare status. 481 this.updateFieldCompare( fieldModel ); 482 483 /* 484 * TODO: This should be moved to the show_field/hide_field file because it is specific to showing and hiding. 485 * Create a radio message here so that the specific JS file can hook into whenModel init. 486 */ 487 fieldModel.on( 'change:visible', this.updateFieldCompare, this ); 488 } 489 }, 490 491 updateCalcCompare: function( calcModel ) { 492 this.updateCompare( calcModel.get( 'value' ) ); 493 }, 494 495 maybeupdateFieldCompare: function( el, fieldModel, keyCode ) { 496 if( 'checkbox' == fieldModel.get( 'type' ) ){ 497 var fieldValue = ( 'checked' == jQuery( el ).attr( 'checked' ) ) ? 1 : 0; 498 } else if( 'listcheckbox' == fieldModel.get( 'type' ) ) { 499 // This field isn't a single element, so we need to reference the fieldModel, instead of the DOM. 500 var fieldValue = fieldModel.get( 'value' ).join(); 501 } else if ( 'listradio' == fieldModel.get( 'type' ) ) { 502 /* 503 * Use the field model's actual selected value rather than jQuery(el).val(). 504 * jQuery(el).val() returns the value attribute of whichever radio button has 505 * focus, even if it has not been selected by the user. When tabbing into a 506 * radio field, the keyup event fires on the focused (but unselected) radio 507 * button, causing jQuery(el).val() to return that option's value and 508 * incorrectly trigger conditions. The field model value only reflects a 509 * genuinely selected option. 510 */ 511 var fieldValue = fieldModel.get( 'value' ); 512 } else if ( 'date' == fieldModel.get ('type' ) ) { 513 var fieldValue = fieldModel.get( 'value' ); 514 var fieldHadValue = ! _.isEmpty( fieldValue ); 515 516 if ( _.isEmpty( fieldValue ) ) { 517 if ( 1 == fieldModel.get( 'date_default' ) ) { 518 var now = new Date(); 519 fieldValue = now.getFullYear() + '/' + ( '0' + ( now.getMonth() + 1 ) ).slice( -2 ) + '/' + ( '0' + now.getDate() ).slice( -2 ); 520 } else { 521 fieldValue = '1970/01/01'; 522 } 523 } 524 525 let date_mode = fieldModel.get( 'date_mode' ); 526 if ( 'undefined' == typeof date_mode ) { // If 'date_mode' is undefined, then we assume it's date_only. 527 date_mode = 'date_only'; 528 } 529 let date = 0; 530 // If we're in time_only mode, then we need to use 1970-01-01 as our date. 531 if ( 'time_only' == fieldModel.get( 'date_mode' ) ) { 532 date = '1970/01/01'; 533 } else { 534 // Parse the submitted value using the field's own configured date_format, 535 // instead of handing a format-dependent string straight to `new Date()`. 536 date = fieldHadValue ? this.normalizeDateToISO( fieldValue, fieldModel ) : fieldValue; 537 } 538 539 // Convert field value into a timestamp 540 let hour = fieldModel.get( 'selected_hour' ); 541 if ( 'undefined' == typeof hour ) { 542 hour = '00'; 543 } 544 545 let minute = fieldModel.get( 'selected_minute' ); 546 if ( 'undefined' == typeof minute ) { 547 minute = '00'; 548 } 549 550 // If we have a date_and_time field, but we haven't selected a date yet, we don't need to compare. 551 if ( 'date_and_time' == date_mode && '1970/01/01' == date ) { 552 fieldValue = false;
553 } else { 554 fieldValue = date + ' ' + hour + ':' + minute + ' UT'; 555 556 let dateObject = new Date( fieldValue ); 557 fieldValue = Math.floor( dateObject.getTime() / 1000 ); 558 } 559 } else { 560 var fieldValue = jQuery( el ).val(); 561 } 562 563 this.updateFieldCompare( fieldModel, null, fieldValue ); 564 }, 565 566 /** 567 * Convert a date field's raw submitted value into a Y/m/d order string 568 * ("normalized ISO"), parsing it according to the field's own date_format 569 * setting rather than assuming YYYY-MM-DD. Falls back to the original string 570 * unchanged if the field's flatpickr instance/format can't be resolved (e.g. 571 * a hidden or programmatically-set field), preserving prior behavior for 572 * those cases. 573 * 574 * @param {string} dateString Raw value straight from the field model. 575 * @param {object} fieldModel Backbone field model for the date field. 576 * @return {string} Y/m/d date string, or the original value if it couldn't be parsed. 577 */ 578 normalizeDateToISO: function( dateString, fieldModel ) { 579 var format = fieldModel.get( 'date_format' ); 580 var el = document.querySelector( "[name='nf-field-" + fieldModel.get( 'id' ) + "']" ); 581 582 if ( ! el || ! el._flatpickr || ! format ) { 583 return dateString; 584 } 585 586 var parsed = el._flatpickr.parseDate( dateString, format ); 587 588 if ( ! parsed || isNaN( parsed.getTime() ) ) { 589 return dateString; 590 } 591 592 return parsed.getFullYear() + '/' + ( '0' + ( parsed.getMonth() + 1 ) ).slice( -2 ) + '/' + ( '0' + parsed.getDate() ).slice( -2 ); 593 }, 594 595 updateCompare: function( value, dateMode ) { 596 var this_val = this.get( 'value' ); 597 598 // if this is a calcModel then let's convert to number for comparison 599 if ( 'calc' === this.get( 'type' ) ) { 600 this_val = Number( this_val ); 601 value = Number( value ); 602 } else if ( 'undefined' != typeof dateMode ) { 603 // The stored condition target may have been created while the field was in a 604 // different date_mode (e.g. a time baked in from Date and Time mode, now that 605 // the field is Date Only). Disregard whichever component (date, or time-of-day) 606 // the current mode doesn't actually capture. 607 value = this.normalizeForDateMode( value, dateMode ); 608 this_val = this.normalizeForDateMode( this_val, dateMode ); 609 } 610 // Check to see if the value of the field model value COMPARATOR the value of our when condition is true. 611 var status = this.compareValues[ this.get( 'comparator' ) ]( value, this_val ); 612 this.set( 'status', status ); 613 }, 614 615 normalizeForDateMode: function( epoch, dateMode ) { 616 if ( false === epoch || null === epoch || 'undefined' == typeof epoch || isNaN( epoch ) ) { 617 return epoch; 618 } 619 620 var DAY_IN_SECONDS = 86400; 621 622 if ( 'date_only' === dateMode ) { 623 return epoch - ( epoch % DAY_IN_SECONDS ); 624 } 625 626 if ( 'time_only' === dateMode ) { 627 return ( ( epoch % DAY_IN_SECONDS ) + DAY_IN_SECONDS ) % DAY_IN_SECONDS; 628 } 629 630 return epoch; 631 }, 632 633 updateFieldCompare: function( fieldModel, val, fieldValue ) { 634 if ( _.isEmpty( fieldValue ) ) { 635 fieldValue = fieldModel.get( 'value' ); 636 } 637 638 var date_mode; 639 640 // Change the value of checkboxes to match the new convention. 641 if( 'checkbox' == fieldModel.get( 'type' ) ) { 642 if( 0 == fieldValue ) { 643 fieldValue = 'unchecked'; 644 } else { 645 fieldValue = 'checked'; 646 } 647 } else if ( 'date' == fieldModel.get( 'type' ) ) { 648 // NF core's fieldDate.js sets the model's 'value' to an object 649 // ({date, hour, minute, ampm}) right at form submission (beforeSubmit), 650 // instead of the plain date string used everywhere else. Extract the date 651 // portion here so normalizeDateToISO() always receives a string — otherwise 652 // its flatpickr parseDate() call receives the object and logs "Invalid date 653 // provided", falling back to the (still-an-object) value unchanged. 654 if ( _.isObject( fieldValue ) ) { 655 fieldValue = fieldValue.date; 656 } 657 658 var fieldHadValue = ! _.isEmpty( fieldValue ); 659 660 if ( _.isEmpty( fieldValue ) ) { 661 if ( 1 == fieldModel.get( 'date_default' ) ) { 662 var now = new Date(); 663 fieldValue = now.getFullYear() + '/' + ( '0' + ( now.getMonth() + 1 ) ).slice( -2 ) + '/' + ( '0' + now.getDate() ).slice( -2 ); 664 } else { 665 fieldValue = '1970/01/01'; 666 } 667 } 668 669 date_mode = fieldModel.get( 'date_mode' ); 670 if ( 'undefined' == typeof date_mode ) { // If 'date_mode' is undefined, then we assume it's date_only. 671 date_mode = 'date_only'; 672 } 673 let date = 0; 674 // If we're in time_only mode, then we need to use 1970-01-01 as our date. 675 if ( 'time_only' == fieldModel.get( 'date_mode' ) ) { 676 date = '1970/01/01'; 677 } else { 678 // Parse the submitted value using the field's own configured date_format, 679 // instead of handing a format-dependent string straight to `new Date()`. 680 date = fieldHadValue ? this.normalizeDateToISO( fieldValue, fieldModel ) : fieldValue; 681 } 682 683 // Convert field value into a timestamp 684 let hour = fieldModel.get( 'selected_hour' ); 685 if ( 'undefined' == typeof hour ) { 686 hour = '00'; 687 } 688 689 let ampm = fieldModel.get( 'selected_ampm' ); 690 if ( 'undefined' != typeof ampm ) { 691 // Convert our hour into 24 hr format. 692 if ( 'pm' == ampm && '12' != hour ) { 693 hour = parseInt( hour ) + 12; 694 } else if ( 'am' == ampm && '12' == hour ) { 695 hour = '00'; 696 } 697 } 698 699 let minute = fieldModel.get( 'selected_minute' ); 700 if ( 'undefined' == typeof minute ) { 701 minute = '00'; 702 } 703 704 // If we have a date_and_time field, but we haven't selected a date yet, we don't need to compare. 705 if ( 'date_and_time' == date_mode && '1970/01/01' == date ) { 706 fieldValue = false;
707 } else { 708 fieldValue = date + ' ' + hour + ':' + minute + ' UT'; 709 710 let dateObject = new Date( fieldValue ); 711 fieldValue = Math.floor( dateObject.getTime() / 1000 ); 712 } 713 } 714 715 this.updateCompare( fieldValue, date_mode ); 716 717 /* 718 * TODO: This should be moved to the show_field/hide_field file because it is specific to showing and hiding. 719 */ 720 if ( ! fieldModel.get( 'visible' ) ) { 721 this.set( 'status', false ); 722 } 723 }, 724 725 compareValues: { 726 'equal': function( a, b ) { 727 return a == b; 728 }, 729 'notequal': function( a, b ) { 730 return a != b; 731 }, 732 'contains': function( a, b ) { 733 if ( jQuery.isArray( a ) ) { 734 /* 735 * If a is an array, then we're searching for an index. 736 */ 737 return a.indexOf( b ) >= 0; 738 } else { 739 /* 740 * If a is a string, then we're searching for a string position. 741 * 742 * If our b value has quotes in it, we want to find that exact word or phrase. 743 */ 744 if ( b.indexOf( '"' ) >= 0 ) { 745 b = b.replace( /['"]+/g, '' ); 746 return new RegExp("\\b" + b + "\\b").test( a ); 747 } 748 return a.toLowerCase().indexOf( b.toLowerCase() ) >= 0; 749 } 750 }, 751 'notcontains': function( a, b ) { 752 return ! this.contains( a, b ); 753 }, 754 'greater': function( a, b ) { 755 /* 756 * In 2.9.x, you could use the greater and less like string count. 757 * i.e. if textbox > (empty string) do something. 758 * This recreates that ability. 759 */ 760 if ( jQuery.isNumeric( b ) ) { 761 return parseFloat( a ) > parseFloat( b ); 762 } else if ( 'string' == typeof a ) { 763 return 0 < a.length; 764 } 765 766 }, 767 'less': function( a, b ) { 768 /* 769 * In 2.9.x, you could use the greater and less like string count. 770 * i.e. if textbox > (empty string) do something. 771 * This recreates that ability. 772 */ 773 if ( jQuery.isNumeric( b ) ) { 774 return parseFloat( a ) < parseFloat( b ); 775 } else if ( 'string' == typeof a ) { 776 return 0 >= a.length; 777 } 778 779 }, 780 'greaterequal': function( a, b ) { 781 return parseFloat( a ) > parseFloat( b ) || parseFloat( a ) == parseFloat( b ); 782 }, 783 'lessequal': function( a, b ) { 784 return parseFloat( a ) < parseFloat( b ) || parseFloat( a ) == parseFloat( b ); 785 } 786 } 787 } ); 788 789 return model; 790} ); 791define( 'models/whenCollection',['models/whenModel'], function( WhenModel ) { 792 var collection = Backbone.Collection.extend( { 793 model: WhenModel, 794 795 initialize: function( models, options ) { 796 this.options = options; 797 } 798 } ); 799 return collection; 800} ); 801define( 'models/conditionModel',[ 'models/whenCollection' ], function( WhenCollection ) { 802 var model = Backbone.Model.extend( { 803 initialize: function( options ) { 804 /* 805 * Our "when" statement will be like: 806 * When field1 == value 807 * AND field2 == value 808 * 809 * We need to create a collection out of this when statement, with each row as a model. 810 */ 811 this.set( 'when', new WhenCollection( this.get( 'when' ), { condition: this } ) ); 812 /* 813 * When we update any of our "when" models' status, check to see if we should send a message. 814 */ 815 this.get( 'when' ).on( 'change:status', this.checkWhen, this ); 816 /* 817 * Check our initial status; 818 * Deferred via setTimeout to allow all field relationships (e.g. Confirm field pairings) 819 * to be fully established before conditions first evaluate on page load. 820 */ 821 setTimeout( function() { 822 this.checkWhen(); 823 }.bind( this ), 0 ); 824 }, 825 826 checkWhen: function() { 827 /* 828 * If we have any OR connectors, then any status being true should trigger pass. 829 * Otherwise, we need every status to be true. 830 */ 831 var statusResults = this.get( 'when' ).pluck( 'status' ); 832 833 var connectors = this.get( 'when' ).pluck( 'connector' ); 834 var allAND = _.every( _.values( connectors ), function( v ) { return v == 'AND' }, this ); 835 if ( allAND ) { 836 var status = _.every( _.values( statusResults ), function(v) { return v; }, this ); 837 } else { 838 var status = _.some( _.values( statusResults ), function(v) { return v; }, this ); 839 } 840 841 if ( status ) { 842 /* 843 * Send out a request for each of our "then" statements. 844 */ 845 _.each( this.get( 'then' ), function( then, index ) { 846 nfRadio.channel( 'condition:trigger' ).request( then.trigger, this, then ); 847 }, this ); 848 } else { 849 /* 850 * Send out a request for each of our "else" statements. 851 */ 852 _.each( this.get( 'else' ), function( elseData, index ) { 853 nfRadio.channel( 'condition:trigger' ).request( elseData.trigger, this, elseData ); 854 }, this ); 855 } 856 } 857 } ); 858 859 return model; 860} ); 861 862define( 'models/conditionCollection',['models/conditionModel'], function( ConditionModel ) { 863 var collection = Backbone.Collection.extend( { 864 model: ConditionModel, 865 866 initialize: function( models, options ) { 867 this.formModel = options.formModel; 868 } 869 } ); 870 return collection; 871} ); 872/** 873 * Initialise condition collection 874 * 875 * @package Ninja Forms Conditional Logic 876 * @copyright (c) 2016 WP Ninjas 877 * @since 3.0 878 */ 879define( 'controllers/initCollection',[ 'models/conditionCollection' ], function( ConditionCollection ) { 880 var controller = Marionette.Object.extend( { 881 initialize: function( formModel ) { 882 this.collection = new ConditionCollection( formModel.get( 'conditions' ), { formModel: formModel } ); 883 this.listenTo(nfRadio.channel('fields'), 'reset:collection', this.resetCollection); 884 }, 885 resetCollection: function( fieldsCollection ) { 886 var formModel = fieldsCollection.options.formModel; 887 this.collection = new ConditionCollection( formModel.get( 'conditions' ), { formModel: formModel } ); 888 } 889 }); 890 891 return controller; 892} ); 893/** 894 * Handle showing/hiding fields 895 * 896 * @package Ninja Forms Conditional Logic 897 * @copyright (c) 2016 WP Ninjas 898 * @since 3.0 899 */ 900define( 'controllers/showHide',[], function() { 901 var controller = Marionette.Object.extend( { 902 initialize: function() { 903 nfRadio.channel( 'condition:trigger' ).reply( 'hide_field', this.hideField, this ); 904 nfRadio.channel( 'condition:trigger' ).reply( 'show_field', this.show
904Field, this ); 905 }, 906 907 hideField: function( conditionModel, then ) { 908 var formId = conditionModel.collection.formModel.get( 'id' ); 909 var targetFieldModel = nfRadio.channel( 'form-' + formId ).request( 'get:fieldByKey', then.key ); 910 911 if( 'undefined' == typeof targetFieldModel ) return; 912 targetFieldModel.set( 'visible', false ); 913 if ( ! targetFieldModel.get( 'clean' ) ) { 914 targetFieldModel.trigger( 'change:value', targetFieldModel ); 915 } 916 917 nfRadio.channel( 'fields' ).request( 'remove:error', targetFieldModel.get( 'id' ), 'required-error' ); 918 919 // For repeater fields, mark child field models as not visible so JS 920 // validation skips their required check on submission. 921 if ( 'repeater' === targetFieldModel.get( 'type' ) ) { 922 this.setRepeaterChildrenVisible( targetFieldModel, false ); 923 } 924 }, 925 926 /** 927 * Set the visible state on all child field models of a Repeater field. 928 * 929 * Child models live inside the Repeater's own sets collection, not in the 930 * top-level form field collection. When visible is false, NF core's 931 * validateModelData skips required validation for those fields. 932 */ 933 setRepeaterChildrenVisible: function( repeaterModel, visible ) { 934 var sets = repeaterModel.get( 'sets' ); 935 if ( ! sets ) return; 936 937 sets.each( function( set ) { 938 var fields = set.get( 'fields' ); 939 if ( ! fields ) return; 940 941 fields.each( function( fieldModel ) { 942 fieldModel.set( 'visible', visible ); 943 if ( ! visible ) { 944 nfRadio.channel( 'fields' ).request( 'remove:error', fieldModel.get( 'id' ), 'required-error' ); 945 } 946 } ); 947 } ); 948 }, 949 950 showField: function( conditionModel, then ) { 951 var targetFieldModel = nfRadio.channel( 'form-' + conditionModel.collection.formModel.get( 'id' ) ).request( 'get:fieldByKey', then.key ); 952 //TODO: Add an error to let the user know the show/hide field is empty. 953 if( 'undefined' == typeof targetFieldModel ) return; 954 targetFieldModel.set( 'visible', true ); 955 if ( ! targetFieldModel.get( 'clean' ) ) { 956 targetFieldModel.trigger( 'change:value', targetFieldModel ); 957 } 958 // For repeater fields, restore child field models to visible so 959 // required validation applies again when the Repeater is shown. 960 if ( 'repeater' === targetFieldModel.get( 'type' ) ) { 961 this.setRepeaterChildrenVisible( targetFieldModel, true ); 962 } 963 if ( 'recaptcha' === targetFieldModel.get( 'type' ) ) { 964 this.renderRecaptcha(); 965 } 966 if ( 'turnstile' === targetFieldModel.get( 'type' ) ) { 967 this.renderTurnstile(); 968 } 969 var viewEl = { el: nfRadio.channel( 'form-' + conditionModel.collection.formModel.get( 'id' ) ).request( 'get:el' ) }; 970 nfRadio.channel( 'form' ).request( 'init:help', viewEl ); 971 }, 972 973 renderRecaptcha: function() { 974 jQuery( '.g-recaptcha' ).each( function() { 975 var callback = jQuery( this ).data( 'callback' ); 976 var fieldID = jQuery( this ).data( 'fieldid' ); 977 if ( typeof window[ callback ] !== 'function' ){ 978 window[ callback ] = function( response ) { 979 nfRadio.channel( 'recaptcha' ).request( 'update:response', response, fieldID ); 980 }; 981 } 982 var opts = { 983 theme: jQuery( this ).data( 'theme' ), 984 sitekey: jQuery( this ).data( 'sitekey' ), 985 callback: callback 986 }; 987 988 grecaptcha.render( jQuery( this )[0], opts ); 989 } ); 990 }, 991 992 renderTurnstile: function() { 993 // Ensure turnstile API is loaded 994 if ( typeof turnstile === 'undefined' ) { 995 return; 996 } 997 998 jQuery( '.cf-turnstile, .nf-cf-turnstile' ).each( function() { 999 var element = this; 1000 var sitekey = jQuery( element ).data( 'sitekey' ); 1001 var fieldID = jQuery( element ).data( 'fieldid' ); 1002 1003 // Skip if no sitekey or already rendered 1004 if ( ! sitekey || jQuery( element ).children().length > 0 ) { 1005 return; 1006 } 1007 1008 try { 1009 // Create callback function for this specific field 1010 var callbackName = 'nfTurnstileCallback_' + fieldID; 1011 1012 // Define the callback function 1013 window[ callbackName ] = function( token ) { 1014 // Update the hidden input field 1015 var input = document.getElementById( 'nf-field-' + fieldID ); 1016 if ( input ) { 1017 input.value = token; 1018 jQuery( input ).trigger( 'change' ); 1019 1020 // Remove error states 1021 jQuery( input ).closest( '.field-wrap' ).removeClass( 'nf-error' ); 1022 jQuery( input ).closest( '.field-wrap' ).find( '.nf-error-msg' ).remove(); 1023 } 1024 1025 // Update via radio channel if available 1026 if ( typeof nfRadio !== 'undefined' && nfRadio.channel ) { 1027 try { 1028 nfRadio.channel( 'turnstile' ).request( 'update:response', token, fieldID ); 1029 } catch( e ) { 1030 // Silent fail 1031 } 1032 } 1033 }; 1034 1035 // Render the turnstile widget 1036 turnstile.render( element, { 1037 sitekey: sitekey, 1038 theme: jQuery( element ).data( 'theme' ) || 'auto', 1039 size: jQuery( element ).data( 'size' ) || 'normal', 1040 callback: callbackName 1041 } ); 1042 1043 } catch( e ) { 1044 // Silent fail for turnstile render errors 1045 } 1046 } ); 1047 } 1048 }); 1049 1050 return controller; 1051} ); 1052/** 1053 * Setting/unsetting required. 1054 * 1055 * @package Ninja Forms Conditional Logic 1056 * @copyright (c) 2019 WP Ninjas 1057 * @since 3.0 1058 */ 1059define( 'controllers/changeRequired',[], function() { 1060 var controller = Marionette.Object.extend( { 1061 initialize: function() { 1062 nfRadio.channel( 'condition:trigger' ).reply( 'set_required', this.setRequired, this ); 1063 nfRadio.channel( 'condition:trigger' ).reply( 'unset_required', this.unsetRequired, this ); 1064 }, 1065 1066 setRequired: function( conditionModel, then ) { 1067 var targetFieldModel = nfRadio.channel( 'form-' + conditionModel.collection.formModel.get( 'id' ) ).request( 'get:fieldByKey', then.key ); 1068 1069 if( 'undefined' == typeof targetFieldModel ) return; 1070 targetFieldModel.set( 'required', 1 ); 1071 targetFieldModel.trigger( 'reRender', targetFieldModel ); 1072 }, 1073 1074 unsetRequired: function( conditionModel, then ) { 1075 var targetFieldModel = nfRadio.channel( 'form-' + conditionModel.collection.formModel.get( 'id' ) ).request( 'get:fieldByKey', then.key ); 1076 1077 if( 'undefined' == typeof targetFieldModel ) return; 1078 targetFieldModel.set( 'required', 0 ); 1079 targetFieldModel.trigger( 'reRender', targetFieldModel ); 1080 // Ensure we resolve any errors when the field is no longer required. 1081 nfRadio.channel( 'fields' ).request( 'remove:error', targetFieldModel.get( 'id' ), 'required-error' ); 1082 } 1083 1084 }); 1085 1086 return controller; 1087} ); 1088/** 1089 * Handle adding or removing an option from our list 1090 * 1091 * @package Ninja Forms Conditional Logic 1092 * @copyright (c) 2016 WP Ninjas 1093 * @since 3.0 1094 */ 1095define( 'controllers/showHideOption',[], function() { 1096 var controller = Marionette.Object.extend( { 1097 initialize: function() { 1098 nfRadio.channel( 'condition:trigger' ).reply( 'show_option', this.showOption, this ); 1099 1100 nfRadio.channel( 'condition:trigger' ).reply( 'hide_option', this.hideOption, this ); 1101 }, 1102 1103 showOption: function( conditionModel, then ) { 1104 var option = this.getOption( conditionModel, then ); 1105 option.visible = true; 1106 this.restoreFieldValue( conditionModel, then, option ); 1107 this.updateFieldModel( conditionModel, then ); 1108 }, 1109 1110 hideOption: function( conditionModel, then ) { 1111 var option = this.getOption( conditionModel, then ); 1112 option.visible = false;
1113 this.applyFallbackValue( conditionModel, then, option ); 1114 this.updateFieldModel( conditionModel, then ); 1115 }, 1116 1117 getFieldModel: function( conditionModel, then ) { 1118 return nfRadio.channel( 'form-' + conditionModel.collection.formModel.get( 'id' ) ).request( 'get:fieldByKey', then.key ); 1119 }, 1120 1121 getOption: function( conditionModel, then ) { 1122 var targetFieldModel = this.getFieldModel( conditionModel, then ); 1123 var options = targetFieldModel.get( 'options' ); 1124 return _.find( options, function( option ) { return option.value == then.value } ); 1125 }, 1126 1127 /** 1128 * If the option being hidden is the field's current value, fall back to the 1129 * first remaining visible option (or blank). The original value is remembered 1130 * so showOption can restore it automatically - unless the user picks a 1131 * different option manually in the meantime (see bindManualOverrideListener). 1132 */ 1133 applyFallbackValue: function( conditionModel, then, hiddenOption ) { 1134 var targetFieldModel = this.getFieldModel( conditionModel, then ); 1135 var currentValue = targetFieldModel.get( 'value' ); 1136 1137 if ( hiddenOption.visible || currentValue != hiddenOption.value ) return; 1138 1139 // Only remember the original value the first time we fall back, so a 1140 // cascade of hides (multiple options hidden at once) still reverts to 1141 // the value the user actually had selected before any of this happened. 1142 if ( ! targetFieldModel.get( 'clAutoFallback' ) ) { 1143 targetFieldModel.set( 'clAutoFallbackValue', currentValue ); 1144 targetFieldModel.set( 'clAutoFallback', true ); 1145 this.bindManualOverrideListener( targetFieldModel ); 1146 } 1147 1148 var options = targetFieldModel.get( 'options' ); 1149 var firstVisibleOption = _.find( options, function( option ) { 1150 return option.visible !== false; 1151 } ); 1152 1153 this.setFieldValue( targetFieldModel, firstVisibleOption ? firstVisibleOption.value : '' ); 1154 }, 1155 1156 /** 1157 * If the option becoming visible is the one we auto-fell-back from, restore 1158 * it - but only while that fallback is still active (i.e. the user hasn't 1159 * manually selected something else since it was hidden). 1160 */ 1161 restoreFieldValue: function( conditionModel, then, shownOption ) { 1162 var targetFieldModel = this.getFieldModel( conditionModel, then ); 1163 1164 if ( ! targetFieldModel.get( 'clAutoFallback' ) ) return; 1165 if ( targetFieldModel.get( 'clAutoFallbackValue' ) != shownOption.value ) return; 1166 1167 this.setFieldValue( targetFieldModel, shownOption.value ); 1168 targetFieldModel.unset( 'clAutoFallback' ); 1169 targetFieldModel.unset( 'clAutoFallbackValue' ); 1170 }, 1171 1172 /** 1173 * Sets the field's value and notifies merge tags / dependent fields, mirroring 1174 * the change:value handling other conditional logic actions (e.g. showHide) use. 1175 */ 1176 setFieldValue: function( targetFieldModel, value ) { 1177 targetFieldModel.set( 'value', value ); 1178 if ( ! targetFieldModel.get( 'clean' ) ) { 1179 targetFieldModel.trigger( 'change:value', targetFieldModel ); 1180 } 1181 }, 1182 1183 /** 1184 * A real user interaction (change/blur on the field itself) means any value 1185 * we auto-assigned as a fallback is no longer "ours" to revert - it's now the 1186 * user's deliberate choice, so clear our tracking and leave it alone. 1187 */ 1188 bindManualOverrideListener: function( targetFieldModel ) { 1189 if ( targetFieldModel.clManualListenerBound ) return; 1190 targetFieldModel.clManualListenerBound = true; 1191 1192 this.listenTo( nfRadio.channel( 'field-' + targetFieldModel.get( 'id' ) ), 'change:field', function() { 1193 targetFieldModel.unset( 'clAutoFallback' ); 1194 targetFieldModel.unset( 'clAutoFallbackValue' ); 1195 } ); 1196 }, 1197 1198 updateFieldModel: function( conditionModel, then ) { 1199 var targetFieldModel = this.getFieldModel( conditionModel, then ); 1200 var options = targetFieldModel.get( 'options' ); 1201 targetFieldModel.set( 'options', options ); 1202 targetFieldModel.trigger( 'reRender' ); 1203 } 1204 }); 1205 1206 return controller; 1207} ); 1208/** 1209 * Handle changing a field's value 1210 * 1211 * @package Ninja Forms Conditional Logic 1212 * @copyright (c) 2016 WP Ninjas 1213 * @since 3.0 1214 */ 1215define( 'controllers/changeValue',[], function() { 1216 var controller = Marionette.Object.extend( { 1217 initialize: function() { 1218 nfRadio.channel( 'condition:trigger' ).reply( 'change_value', this.changeValue, this ); 1219 }, 1220 1221 changeValue: function( conditionModel, then ) { 1222 var targetFieldModel = nfRadio.channel( 'form-' + conditionModel.collection.formModel.get( 'id' ) ).request( 'get:fieldByKey', then.key ); 1223 /* 1224 * If we have a checkbox then we need to change the value that is set 1225 * of the then variable to a 1 or 0 to re-render on the front end when 1226 * the condition is met. 1227 */ 1228 if( 'checkbox' == targetFieldModel.get( 'type' ) ) { 1229 // We also need to do the opposite of the value that is in the changed model. 1230 if( 'unchecked' == targetFieldModel.changed.value ) { 1231 then.value = 1; 1232 } else if( 'checked' == targetFieldModel ) { 1233 then.value = 0; 1234 } 1235 } 1236 /* 1237 * Change the value of our field model, and then trigger a re-render of its view. 1238 */ 1239 targetFieldModel.set( 'value', then.value ); 1240 targetFieldModel.trigger( 'reRender', targetFieldModel ); 1241 }, 1242 1243 }); 1244 return controller; 1245} ); 1246/** 1247 * Handle selecting/deselecting list options 1248 * 1249 * @package Ninja Forms Conditional Logic 1250 * @copyright (c) 2016 WP Ninjas 1251 * @since 3.0 1252 */ 1253define( 'controllers/selectDeselect',[], function() { 1254 var controller = Marionette.Object.extend( { 1255 initialize: function() { 1256 nfRadio.channel( 'condition:trigger' ).reply( 'select_option', this.selectOption, this ); 1257 1258 nfRadio.channel( 'condition:trigger' ).reply( 'deselect_option', this.deselectOption, this ); 1259 }, 1260 1261 selectOption: function( conditionModel, then ) { 1262 /* 1263 * Get our field model and set this option's "selected" property to 1 1264 */ 1265 var targetFieldModel = nfRadio.channel( 'form-' + conditionModel.collection.formModel.get( 'id' ) ).request( 'get:fieldByKey', then.key ); 1266 1267 1268 if( _.contains( [ 'listselect', 'listcountry', 'liststate' ], targetFieldModel.get( 'type' ) ) ) { // TODO: Make this more dynamic. 1269 targetFieldModel.set('clean', false); // Allows for changes to default values. 1270 } 1271 1272 var options = targetFieldModel.get( 'options' ); 1273 1274 var option = _.find( options, { value: then.value } ); 1275 option.selected = 1; 1276 1277 targetFieldModel.set( 'options', options ); 1278 1279 if( _.contains( [ 'listselect', 'listcountry', 'liststate' ], targetFieldModel.get( 'type' ) ) ) { // TODO: Make this more dynamic. 1280 targetFieldModel.set( 'value', option.value ); // Propagate the selected option to the model's value. 1281 } else { 1282 var value = targetFieldModel.get( 'value' ); 1283 if ( _.isArray( value ) ) { 1284 if ( 0 > value.indexOf( option.value ) ) { 1285 value.push( option.value ); 1286 // Set the value to nothing so it knows that something has changed. 1287 targetFieldModel.set( 'value', '' ); 1288 } 1289 } else { 1290 value = option.value; 1291 } 1292 1293 targetFieldModel.set( 'value', value ); // Propagate the selected option to the model's value. 1294 } 1295 1296 /* 1297 * Re render our field 1298 */ 1299 targetFieldModel.trigger( 'reRender', targetFieldModel ); 1300 }, 1301 1302 deselectOption: function( conditionModel, then ) { 1303 /*
1304 * When we are trying to deselect our option, we need to change it's "selected" property to 0 AND change its value. 1305 */ 1306 var targetFieldModel = nfRadio.channel( 'form-' + conditionModel.collection.formModel.get( 'id' ) ).request( 'get:fieldByKey', then.key ); 1307 1308 /* 1309 * Set "selected" to 0. 1310 */ 1311 var options = targetFieldModel.get( 'options' ); 1312 var option = _.find( options, { value: then.value } ); 1313 option.selected = 0; 1314 targetFieldModel.set( 'options', options ); 1315 1316 /* 1317 * Update our value 1318 */ 1319 var currentValue = targetFieldModel.get( 'value' ); 1320 if ( _.isArray( currentValue ) ) { 1321 currentValue = _.without( currentValue, then.value ); 1322 } else { 1323 currentValue = ''; 1324 } 1325 targetFieldModel.set( 'value', currentValue ); 1326 1327 /* 1328 * Re render our field 1329 */ 1330 targetFieldModel.trigger( 'reRender', targetFieldModel ); 1331 }, 1332 1333 }); 1334 1335 return controller; 1336} ); 1337/** 1338 * Keep an internal record for which actions are active and deactive. 1339 * 1340 * @package Ninja Forms Conditional Logic 1341 * @copyright (c) 2016 WP Ninjas 1342 * @since 3.0 1343 */ 1344define( 'controllers/actions',[], function() { 1345 var controller = Marionette.Object.extend( { 1346 actions: {}, 1347 1348 initialize: function() { 1349 /* 1350 * Listen for activate/deactivate action messages. 1351 */ 1352 nfRadio.channel( 'condition:trigger' ).reply( 'activate_action', this.activateAction, this ); 1353 nfRadio.channel( 'condition:trigger' ).reply( 'deactivate_action', this.deactivateAction, this ); 1354 1355 /* 1356 * Reply to requests for action status. 1357 */ 1358 nfRadio.channel( 'actions' ).reply( 'get:status', this.getStatus, this ); 1359 }, 1360 1361 activateAction: function( conditionModel, thenObject ) { 1362 this.actions[ thenObject.key ] = true; 1363 console.log( 'activate action' ); 1364 }, 1365 1366 deactivateAction: function( conditionModel, thenObject ) { 1367 console.log( 'deactivate action' ); 1368 this.actions[ thenObject.key ] = false; 1369 }, 1370 1371 getStatus: function( $id ) { 1372 return this.actions[ $id ]; 1373 } 1374 }); 1375 1376 return controller; 1377} ); 1378var nfRadio = Backbone.Radio; 1379 1380require( [ 'controllers/initCollection', 'controllers/showHide', 'controllers/changeRequired', 'controllers/showHideOption', 'controllers/changeValue', 'controllers/selectDeselect', 'controllers/actions' ], function( InitCollection, ShowHide, ChangeRequired, ShowHideOption, ChangeValue, SelectDeselect, Actions ) { 1381 1382 var NFConditionalLogic = Marionette.Application.extend( { 1383 1384 initialize: function( options ) { 1385 this.listenTo( nfRadio.channel( 'form' ), 'after:loaded', this.loadControllers ); 1386 }, 1387 1388 loadControllers: function( formModel ) { 1389 new ShowHide(); 1390 new ChangeRequired(); 1391 new ShowHideOption(); 1392 new ChangeValue(); 1393 new SelectDeselect(); 1394 new Actions(); 1395 new InitCollection( formModel ); 1396 }, 1397 1398 onStart: function() { 1399 1400 } 1401 } ); 1402 1403 var nfConditionalLogic = new NFConditionalLogic(); 1404 nfConditionalLogic.start(); 1405} ); 1406define("main", function(){}); 1407 1408}()); 1409//# 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.