1( function( $ ) { 2 3 window.GWDTCalc = function( args ) { 4 5 var self = this; 6 7 // copy all args to current object: (list expected props) 8 for( prop in args ) { 9 if( args.hasOwnProperty( prop ) ) 10 self[prop] = args[prop]; 11 } 12 13 self.rebind = function () { 14 $.each(self.elementsToBind, function(formId, elements) { 15 $.each(elements, function(_, toBind) { 16 $inputs = $(); 17 18 $.each(toBind.dateFields, function(_, dateField) { 19 $inputs = $inputs.add($( '#field_' + formId + '_' + dateField.id ).find( 'input, select' )); 20 }); 21 22 self.bindEvents($inputs, toBind.calcField, toBind.calcObj); 23 }); 24 }); 25 }; 26 27 self.init = function() { 28 29 self.elementsToBind = {}; 30 31 /** 32 * Reset on page change to rebind 33 */ 34 jQuery(document).on('gform_post_render', self.rebind); 35 36 gform.addFilter( 'gform_calculation_formula', function( formula, calcField, formId, calcObj ) { 37 38 var calcFieldId = calcField.field_id, 39 // Parse weekdays/weekendDays merge tags first so nested Date merge tags can be processed accurately. 40 customMatches = GFMergeTag.parseMergeTags( formula, /{(weekdays|weekendDays):(?:{.*?:([0-9]+)}),(?:{.*?:([0-9]+)})}/ ); 41 42 $.each( customMatches, function( index, match ) { 43 44 var fullMatch = match[0], 45 customType = match[1], 46 startDate = self.getDateFieldValue( self.getDateField( calcFieldId, match[2] ), self.formId ), 47 endDate = self.getDateFieldValue( self.getDateField( calcFieldId, match[3] ), self.formId ), 48 value = 0; 49 50 if( startDate > 0 && endDate > 0 ) { 51 52 switch( customType ) { 53 case 'weekdays': 54 value = self.calcWeekDays( new Date( startDate * 1000 ), new Date( endDate * 1000 ) ); 55 break; 56 case 'weekendDays': 57 value = self.calcWeekendDays( new Date( startDate * 1000 ), new Date( endDate * 1000 ) ); 58 break; 59 default: 60 break; 61 } 62 63 } 64 65 // Wrap value in parentheses to handle double-negatives 66 formula = formula.replace( fullMatch, '(' + value + ')' ); 67 68 } ); 69 70 var matches = typeof window.GFMergeTag ? GFMergeTag.parseMergeTags( formula ) : getMatchGroups( formula, calcObj.patt ); 71 if( matches.length > 0 ) { 72 var calcFieldData = self.getCalcFieldData( calcFieldId ); 73 } 74 75 $.each( matches, function( index, match ) { 76 77 var fullMatch = match[0], 78 inputId = match[1], 79 modifier = match[4], 80 fieldId = parseInt( inputId ), 81 dateField = self.getDateField( calcFieldId, fieldId ); 82 83 if( ! dateField ) { 84 return; // continue 85 } 86 87 var $inputs = $( '#field_' + formId + '_' + dateField.id ).find( 'input, select' ), 88 value = self.getDateFieldValue( dateField, formId, $inputs ); 89 90 if( modifier ) { 91 value = self.processModifier( value, modifier ); 92 } 93 94 if( modifier != 'age' ) { 95 value = self.convertToUnit( value, calcFieldData.unit ); 96 } 97 98 // Wrap value in parentheses to handle double-negatives 99 formula = formula.replace( fullMatch, '(' + value + ')' ); 100 101 if ( !(formId in self.elementsToBind) ) { 102 self.elementsToBind[formId] = {}; 103 } 104 105 self.bindEvents($inputs, calcField, calcObj); 106 107 if ( self.elementsToBind[formId][calcFieldId] ) { 108 self.elementsToBind[formId][calcFieldId].dateFields.push(dateField); 109 110 return; 111 } 112 113 /** 114 * Mark field to be bound on page change. 115 * 116 * @type {{calcField: *, dateField: *, calcObj: *}} 117 */ 118 self.elementsToBind[formId][calcFieldId] = { 119 calcField: calcField, 120 calcObj: calcObj, 121 dateFields: [dateField], 122 }; 123 124 } ); 125 126 var staticMergeTags = [ 'today', 'now' ]; 127 128 $.each( staticMergeTags, function( index, mergeTag ) { 129 130 if( formula.indexOf( '{' + mergeTag + '}' ) === -1 ) { 131 return; 132 } 133 134 var value = 0, 135 calcFieldData = self.getCalcFieldData( calcFieldId ); 136 137 if( ! calcFieldData ) { 138 return; 139 } 140 141 switch( mergeTag ) { 142 case 'today': 143 value = self.getMomentToday( { hour: 0, minute: 0, seconds: 0 } ).format('X'); 144 value = self.convertToUnit( value, calcFieldData.unit ); 145 break; 146 case 'now': 147 value = self.getMoment(undefined, false).format('X'); 148 value = self.convertToUnit( value, calcFieldData.unit ); 149 break; 150 default: 151 break; 152 } 153 154 var regex = new RegExp( '{' + mergeTag + '}', 'g' ); 155 156 // Wrap value in parentheses to handle double-negatives 157 formula = formula.replace( regex, '(' + value + ')' ); 158 159 } ); 160 161 return formula; 162 } ); 163 164 // bit of a hack but an easy way to force calculations to run again now that our filters are in place 165 $( document ).trigger( 'gform_post_conditional_logic' ); 166 167 }; 168 169 /** 170 * @param time 171 * @param keepLocalTime We haven't figured out a rule behind toggling this keepLocalTime. We need to figure out 172 * a rule for using this. 173 * 174 * @param sourceTimeFormat 175 * @return {*|number} 176 */ 177 self.getMoment = function ( time, keepLocalTime, sourceTimeFormat ) { 178 179 if (typeof keepLocalTime === 'undefined') { 180 keepLocalTime = true; 181 } 182 183 var offset = parseInt(GPDTC.GMT_OFFSET); 184 185 if (offset === 0) { 186 return moment.utc(time, sourceTimeFormat); 187 } 188 189 return moment(time, sourceTimeFormat).utcOffset(offset, keepLocalTime); 190 191 }; 192 193 self.onChangeFactory = function(calcField, calcObj) { 194 return function() { 195 calcObj.bindCalcEvent( $( this ).attr( 'id' ), calcField, self.formId, 0 ); 196 }; 197 }; 198 199 self.bindEvents = function( $inputs, calcField, calcObj ) { 200
201 $inputs 202 .off('change.gpdtc') 203 .on('change.gpdtc', self.onChangeFactory(calcField, calcObj)); 204 205 $inputs 206 .not('select') 207 .off('keyup.gpdtc') 208 .on('keyup.gpdtc', self.onChangeFactory(calcField, calcObj)); 209 210 }; 211 212 self.getCalcFieldData = function( fieldId ) { 213 214 var calcFieldData = false; 215 216 $.each( self.dateFieldsData, function( calcFieldId, _calcFieldData ) { 217 if( calcFieldId == fieldId ) { 218 calcFieldData = _calcFieldData; 219 return false; 220 } 221 } ); 222 223 return calcFieldData; 224 }; 225 226 self.getDateField = function( calcFieldId, fieldId ) { 227 228 var dateField = false, 229 calcFieldData = self.getCalcFieldData( calcFieldId ); 230 231 if( ! calcFieldData ) { 232 return false; 233 } 234 235 $.each( calcFieldData.fields, function( i, _dateField ) { 236 if( fieldId == _dateField.id ) { 237 dateField = _dateField; 238 return false; 239 } 240 } ); 241 242 return dateField; 243 }; 244 245 self.getDateFieldValue = function( dateField, formId, $inputs ) { 246 247 var isVisible = window['gf_check_field_rule'] ? gf_check_field_rule( formId, dateField.id, true, '' ) == 'show' : true, 248 $inputs = typeof $inputs == 'undefined' ? $( '#field_' + formId + '_' + dateField.id ).find( 'input, select' ) : $inputs, 249 value = 0; 250 251 if( $inputs.length <= 0 || ! isVisible ) { 252 return value; 253 } 254 255 switch( dateField.type ) { 256 257 case 'date': 258 259 var formatBits = dateField.dateFormat.split( '_' ), 260 mdy = formatBits[0];/*, 261 separator = formatBits.length > 1 ? formatBits[1] : 'slash';*/ 262 263 switch( dateField.dateType ) { 264 case 'datefield': 265 case 'datedropdown': 266 var month = $inputs.eq( mdy.indexOf( 'm' ) ).val(), 267 day = $inputs.eq( mdy.indexOf( 'd' ) ).val(), 268 year = $inputs.eq( mdy.indexOf( 'y' ) ).val(), 269 missingData = ! month || ! day || ! year, 270 datetime = missingData ? false : self.getMoment( month + '/' + day + '/' + year, false, 'M/D/YYYY' ); 271 break; 272 case 'datepicker': 273 var momentFormat = mdy.toUpperCase().split( '' ).join( '/' ).replace( 'Y', 'YYYY' ), 274 datetime = $inputs.val() ? self.getMoment( $inputs.val(), true, momentFormat ) : false; 275 break; 276 default: 277 break; 278 } 279 280 // 'X' is for Unix Timestamp in moment.js 281 var timestamp = datetime === false ? 0 : datetime.format( 'X' ); 282 283 break; 284 285 case 'time': 286 287 var timestamp = self.getMoment(undefined, false).format( 'X' ), 288 hour = parseInt($inputs.eq( 0 ).val()), 289 min = $inputs.eq( 1 ).val(), 290 ampm = $inputs.eq( 2 ).val(), 291 missingData = ! hour || ! min; 292 293 if( ! missingData ) { 294 295 if (ampm === 'am' && hour === 12) { 296 hour = 0; 297 } 298 299 if (ampm === 'pm' && hour === 12) { 300 hour = 12; 301 } 302 303 if (ampm === 'pm' && hour !== 12) { 304 hour += 12; 305 } 306 307 datetime = self.getMomentToday( { hour: hour, minute: parseInt(min) } ); 308 timestamp = datetime.toDate().getTime() / 1000; 309 310 } 311 312 break; 313 314 default: 315 break; 316 317 } 318 319 value = timestamp; 320 321 return value; 322 }; 323 324 self.getMomentToday = function (timeObj) { 325 var now = self.getMoment(undefined, false); 326 327 return self.getMoment($.extend({}, {year: now.year(), month: now.month(), day: now.date()}, timeObj)); 328 }; 329 330 self.processModifier = function( value, modifier ) { 331 332 switch( modifier ) { 333 case 'age': 334 335 if( Math.abs( value ) > 0 ) { 336 337 // @props: https://gist.github.com/richardW8k/ac8b0f24c70114e82fb3 338 var today = new Date(), 339 birthDate = new Date( value * 1000 ), 340 age = today.getFullYear() - birthDate.getFullYear(), 341 m = today.getMonth() - birthDate.getMonth(); 342 343 if( m < 0 || ( m === 0 && today.getDate() < birthDate.getDate() ) ) { 344 age--; 345 } 346 347 value = age; 348 349 } 350 351 break; 352 default: 353 break; 354 } 355 356 return value; 357 }; 358 359 self.convertToUnit = function( value, unit ) { 360 //return value / unit.unit; 361 if( parseInt( value ) === 0 ) { 362 return 0; 363 } 364 365 var mo = self.getMoment( value * 1000 ), 366 diff = mo.diff( '1970-01-01', unit.slug, true ); 367 368 return diff; 369 }; 370 371 self.calcWeekDays = function( startDate, endDate ) { 372 return self.calcDays( startDate, endDate, 'weekdays' ); 373 }; 374 375 self.calcWeekendDays = function( startDate, endDate ) { 376 return self.calcDays( startDate, endDate, 'weekendDays' ); 377 }; 378 379 self.calcDays = function( startDate, endDate, mode ) { 380 381 if( endDate < startDate ) { 382 return 0; 383 } 384 385 if( typeof mode == 'undefined' ) { 386 mode = 'weekdays'; 387 } 388 389 // start just after midnight 390 startDate.setHours( 0, 0, 0, 1 ); 391 392 // end just before midnight 393 endDate.setHours( 23, 59, 59, 999 ); 394 395 var weekdays = 0, 396 weekendDays = 0; 397 398 while( startDate < endDate ) { 399 if( startDate.getDay() === 0 || startDate.getDay() == 6 ) { 400 weekendDays++; 401 } else { 402 weekdays++; 403 } 404 startDate.setDate( startDate.getDate() + 1 ); 405 } 406 407 var days = mode == 'weekdays' ? weekdays : weekendDays; 408 409 return Math.round( days ); 410 }; 411 412 self.init(); 413 414 } 415 416} )( jQuery );
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.