Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save phillipwilhelm/af79bf4d9492617ca2e81936d58d2883 to your computer and use it in GitHub Desktop.
Save phillipwilhelm/af79bf4d9492617ca2e81936d58d2883 to your computer and use it in GitHub Desktop.
Gravity Wiz // Gravity Forms // Rounding by Increment
<?php
/**
* Gravity Wiz // Gravity Forms // Rounding by Increment
*
* Provides a variety of rounding functions for Gravity Form Number fields powered by the CSS class setting for each field. Functions include:
*
* + rounding to an increment (i.e. increment of 100 would round 1 to 100, 149 to 100, 150 to 200, etc) | class: 'gw-round-100'
* + rounding up by an increment (i.e. increment of 50 would round 1 to 50, 51 to 100, 149 to 150, etc) | class: 'gw-round-up-50'
* + rounding down by an increment (i.e. increment of 25 would round 1 to 0, 26 to 25, 51 to 50, etc) | class: 'gw-round-down-25'
* + rounding up to a specific minimum (i.e. min of 50 would round 1 to 50, 51 and greater would not be rounded) | class: 'gw-round-min-50'
* + rounding down to a specific maximum (i.e. max of 25 would round 26 to 25, 25 and below would not be rounded) | class: 'gw-round-max-25'
*
* @version 1.1
* @author David Smith <[email protected]>
* @license GPL-2.0+
* @link http://gravitywiz.com/rounding-increments-gravity-forms/
*/
class GW_Rounding {
private static $instance = null;
protected static $is_script_output = false;
protected $class_regex = 'gw-round-(\w+)-?(\w+)?';
public static function get_instance() {
if( null == self::$instance )
self::$instance = new self;
return self::$instance;
}
private function __construct( $args = array() ) {
// make sure we're running the required minimum version of Gravity Forms
if( ! property_exists( 'GFCommon', 'version' ) || ! version_compare( GFCommon::$version, '1.8', '>=' ) )
return;
// time for hooks
add_filter( 'gform_pre_render', array( $this, 'prepare_form_and_load_script' ) );
add_filter( 'gform_register_init_scripts', array( $this, 'add_init_script' ) );
add_filter( 'gform_enqueue_scripts', array( $this, 'enqueue_form_scripts' ) );
add_action( 'gform_pre_submission', array( $this, 'override_submitted_value' ), 10, 5 );
add_filter( 'gform_calculation_result', array( $this, 'override_submitted_calculation_value' ), 10, 5 );
}
function prepare_form_and_load_script( $form ) {
if( ! $this->is_applicable_form( $form ) ) {
return $form;
}
if( ! self::$is_script_output ) {
$this->output_script();
}
foreach( $form['fields'] as &$field ) {
if( preg_match( $this->get_class_regex(), $field['cssClass'] ) ) {
$field['cssClass'] .= ' gw-rounding';
}
}
return $form;
}
function output_script() {
?>
<script type="text/javascript">
var GWRounding;
( function( $ ) {
GWRounding = function( args ) {
var self = this;
// copy all args to current object: (list expected props)
for( prop in args ) {
if( args.hasOwnProperty( prop ) )
self[prop] = args[prop];
}
self.init = function() {
self.fieldElems = $( '#gform_wrapper_' + self.formId + ' .gw-rounding' );
self.parseElemActions( self.fieldElems );
self.bindEvents();
}
self.parseElemActions = function( elems ) {
elems.each( function() {
var cssClasses = $( this ).attr( 'class' ),
roundingActions = self.parseActions( cssClasses );
$( this ).data( 'gw-rounding', roundingActions );
} );
}
self.parseActions = function( str ) {
var matches = getMatchGroups( String( str ), new RegExp( self.classRegex.replace( /\\/g, '\\' ), 'i' ) ),
roundingActions = [];
for( var i = 0; i < matches.length; i++ ) {
var action = matches[i][1],
actionValue = matches[i][2];
if( typeof actionValue == 'undefined' ) {
actionValue = action;
action = 'round';
}
var roundingAction = {
'action': action,
'actionValue': actionValue
};
roundingActions.push( roundingAction );
}
return roundingActions;
}
self.bindEvents = function() {
self.fieldElems.find( 'input' ).each( function() {
self.applyRoundingActions( $( this ) );
} ).blur( function() {
self.applyRoundingActions( $( this ) );
} );
gform.addFilter( 'gform_calculation_result', function( result, formulaField, formId, calcObj ) {
var $input = $( '#input_' + formId + '_' + formulaField.field_id )
$field = $input.parents( '.gfield' );
if( $field.hasClass( 'gw-rounding' ) ) {
result = self.getRoundedValue( $input, result );
}
return result;
} );
}
self.applyRoundingActions = function( $input ) {
var value = self.getRoundedValue( $input );
if( $input.val() != value ) {
$input.val( value ).change();
}
}
self.getRoundedValue = function( $input, value ) {
var $field = $input.parents( '.gfield' ),
actions = $field.data( 'gw-rounding' );
// allows setting the 'gw-rounding' data for an element to null and it will be reparsed
if( actions === null ) {
self.parseElemActions( $field );
actions = $field.data( 'gw-rounding' );
}
if( typeof actions == 'undefined' || actions === false || actions.length <= 0 ) {
return;
}
if( typeof value == 'undefined' ) {
value = $input.val();
}
if( value == '' ) {
value = '';
} else {
for( var i = 0; i < actions.length; i++ ) {
value = GWRounding.round( value, actions[i].actionValue, actions[i].action );
}
}
return isNaN( value ) ? '' : value;
}
GWRounding.round = function( value, actionValue, action ) {
var interval, base, min, max;
value = parseInt( value );
actionValue = parseInt( actionValue );
switch( action ) {
case 'min':
min = actionValue;
if( value < min ) {
value = min;
}
break;
case 'max':
max = actionValue;
if( value > max ) {
value = max;
}
break;
case 'up':
interval = actionValue;
base = Math.ceil( value / interval );
value = base * interval;
break;
case 'down':
interval = actionValue;
base = Math.floor( value / interval );
value = base * interval;
break;
default:
interval = actionValue;
base = Math.round( value / interval );
value = base * interval;
break;
}
return parseInt( value );
}
self.init();
}
} )( jQuery );
</script>
<?php
self::$is_script_output = true;
}
function add_init_script( $form ) {
if( ! $this->is_applicable_form( $form ) ) {
return;
}
$args = array(
'formId' => $form['id'],
'classRegex' => $this->class_regex
);
$script = 'new GWRounding( ' . json_encode( $args ) . ' );';
GFFormDisplay::add_init_script( $form['id'], 'gw_rounding', GFFormDisplay::ON_PAGE_RENDER, $script );
}
function enqueue_form_scripts( $form ) {
if( $this->is_applicable_form( $form ) ) {
wp_enqueue_script( 'gform_gravityforms' );
}
}
function override_submitted_value( $form ) {
foreach( $form['fields'] as $field ) {
if( $this->is_applicable_field( $field ) ) {
$value = $this->process_rounding_actions( rgpost( "input_{$field['id']}" ), $this->get_rounding_actions( $field ) );
$_POST[ "input_{$field['id']}" ] = $value;
}
}
}
function override_submitted_calculation_value( $result, $formula, $field, $form, $entry ) {
if( $this->is_applicable_field( $field ) ) {
$result = $this->process_rounding_actions( $result, $this->get_rounding_actions( $field ) );
}
return $result;
}
function process_rounding_actions( $value, $actions ) {
foreach( $actions as $action ) {
$value = $this->round( $value, $action['action'], $action['action_value'] );
}
return $value;
}
function round( $value, $action, $action_value ) {
$value = intval( $value );
$action_value = intval( $action_value );
switch( $action ) {
case 'min':
$min = $action_value;
if( $value < $min ) {
$value = $min;
}
break;
case 'max':
$max = $action_value;
if( $value > $max ) {
$value = $max;
}
break;
case 'up':
$interval = $action_value;
$base = ceil( $value / $interval );
$value = $base * $interval;
break;
case 'down':
$interval = $action_value;
$base = floor( $value / $interval );
$value = $base * $interval;
break;
default:
$interval = $action_value;
$base = round( $value / $interval );
$value = $base * $interval;
break;
}
return intval( $value );
}
// # HELPERS
function is_applicable_form( $form ) {
foreach( $form['fields'] as $field ) {
if( $this->is_applicable_field( $field ) ) {
return true;
}
}
return false;
}
function is_applicable_field( $field ) {
return preg_match( $this->get_class_regex(), rgar( $field, 'cssClass' ) ) == true;
}
function get_class_regex() {
return "/{$this->class_regex}/";
}
function get_rounding_actions( $field ) {
$actions = array();
preg_match_all( $this->get_class_regex(), rgar( $field, 'cssClass' ), $matches, PREG_SET_ORDER );
foreach( $matches as $match ) {
list( $full_match, $action, $action_value ) = array_pad( $match, 3, false );
if( $action_value === false ) {
$action_value = $action;
$action = 'round';
}
$action = array(
'action' => $action,
'action_value' => $action_value
);
$actions[] = $action;
}
return $actions;
}
}
function gw_rounding() {
return GW_Rounding::get_instance();
}
gw_rounding();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment