| |
| <?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| class GW_Populate_Date {
|
|
|
| protected static $is_script_output = false;
|
|
|
| private $_args = array();
|
| private $_field_values = array();
|
|
|
| public function __construct( $args = array() ) {
|
|
|
|
|
| $this->_args = wp_parse_args( $args, array(
|
| 'form_id' => false,
|
| 'target_field_id' => false,
|
| 'source_field_id' => false,
|
| 'format' => '',
|
| 'modifier' => '',
|
| 'min_date' => false,
|
| 'enable_i18n' => false,
|
| 'override_on_submission' => false,
|
| 'utc_offset' => get_option( 'gmt_offset' ),
|
| ) );
|
|
|
| $this->_field_values = array();
|
|
|
| if ( ! $this->_args['form_id'] || ! $this->_args['target_field_id'] ) {
|
| return;
|
| }
|
|
|
|
|
| add_action( 'init', array( $this, 'init' ) );
|
|
|
| }
|
|
|
| public function init() {
|
|
|
|
|
| if ( ! property_exists( 'GFCommon', 'version' ) || ! version_compare( GFCommon::$version, '1.8', '>=' ) ) {
|
| return;
|
| }
|
|
|
| if ( $this->_args['source_field_id'] ) {
|
| add_filter( 'gform_pre_render', array( $this, 'load_form_script' ) );
|
| add_filter( 'gform_register_init_scripts', array( $this, 'add_init_script' ) );
|
| add_filter( 'gform_enqueue_scripts', array( $this, 'enqueue_form_scripts' ) );
|
| } else {
|
|
|
| add_filter( 'gform_pre_render', array( $this, 'populate_date_on_pre_render' ), 8 );
|
| }
|
|
|
| if ( $this->_args['override_on_submission'] ) {
|
| add_action( 'gform_pre_submission', array( $this, 'populate_date_on_pre_submission' ) );
|
| }
|
|
|
| }
|
|
|
| public function enqueue_form_scripts( $form ) {
|
| if ( $this->is_applicable_form( $form ) ) {
|
| wp_enqueue_script( 'moment', 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment.min.js' );
|
| add_filter( 'gform_noconflict_scripts', function( $scripts ) {
|
| $scripts[] = 'moment';
|
| return $scripts;
|
| } );
|
| }
|
| }
|
|
|
| public function populate_date_on_pre_render( $form ) {
|
|
|
| if ( ! $this->is_applicable_form( $form ) ) {
|
| return $form;
|
| }
|
|
|
| foreach ( $form['fields'] as &$field ) {
|
| if ( $field['id'] == $this->_args['target_field_id'] ) {
|
|
|
| $key = sprintf( 'gwpd_%d_%d', $form['id'], $field['id'] );
|
| $value = $this->get_modified_date( $field );
|
|
|
| $field['allowsPrepopulate'] = true;
|
| $field['inputName'] = $key;
|
|
|
| $this->_field_values[ $key ] = $value;
|
|
|
| add_filter( "gform_field_value_{$key}", array( $this, 'set_field_value' ), 10, 3 );
|
|
|
| }
|
| }
|
|
|
| return $form;
|
| }
|
|
|
| public function set_field_value( $value, $field, $name ) {
|
| if ( isset( $this->_field_values[ $name ] ) ) {
|
| $value = $this->_field_values[ $name ];
|
| }
|
| return $value;
|
| }
|
|
|
| public function populate_date_on_pre_submission( $form ) {
|
|
|
| if ( ! $this->is_applicable_form( $form ) ) {
|
| return;
|
| }
|
|
|
| foreach ( $form['fields'] as &$field ) {
|
| if ( $field['id'] == $this->_args['target_field_id'] ) {
|
|
|
| $timestamp = false;
|
|
|
| if ( $this->_args['source_field_id'] ) {
|
| $timestamp = $this->get_source_timestamp( GFFormsModel::get_field( $form, $this->_args['source_field_id'] ) );
|
| }
|
|
|
| $value = $this->get_modified_date( $field, $timestamp );
|
|
|
| if ( $value ) {
|
| $_POST[ "input_{$field['id']}" ] = $value;
|
| }
|
| }
|
| }
|
|
|
| }
|
|
|
| public function get_source_timestamp( $field ) {
|
|
|
| $raw = rgpost( 'input_' . $field['id'] );
|
| if ( is_array( $raw ) ) {
|
| $raw = array_filter( $raw );
|
| }
|
|
|
| switch ( $field->type ) {
|
| case 'time':
|
| list( $hour, $minute, $ampm ) = array_pad( $raw, 3, false );
|
| if ( $ampm ) {
|
| $ampm = strtolower( $ampm );
|
| if ( $ampm === 'pm' ) {
|
| $hour -= 12;
|
| } elseif ( $ampm === 'am' && (int) $hour === 12 ) {
|
| $hour = 0;
|
| }
|
| }
|
| $timestamp = mktime( $hour, $minute );
|
| break;
|
| case 'date':
|
| default:
|
| list( $format, $divider ) = $field['dateFormat'] ? array_pad( explode( '_', $field['dateFormat'] ), 2, 'slash' ) : array( 'mdy', 'slash' );
|
| $dividers = array(
|
| 'slash' => '/',
|
| 'dot' => '.',
|
| 'dash' => '-',
|
| );
|
|
|
| if ( empty( $raw ) ) {
|
|
|
| $raw = date( implode( $dividers[ $divider ], str_split( $format ) ) );
|
| }
|
|
|
| $date = ! is_array( $raw ) ? explode( $dividers[ $divider ], $raw ) : $raw;
|
|
|
| $month = $date[ strpos( $format, 'm' ) ];
|
| $day = $date[ strpos( $format, 'd' ) ];
|
| $year = $date[ strpos( $format, 'y' ) ];
|
|
|
| $timestamp = mktime( 0, 0, 0, $month, $day, $year );
|
|
|
| break;
|
| }
|
|
|
| return $timestamp;
|
| }
|
|
|
| public function get_modified_date( $field, $timestamp = false ) {
|
|
|
| if ( ! $timestamp ) {
|
|
|
| $timestamp = current_time( 'timestamp' );
|
| }
|
|
|
| $target_is_date_field = GFFormsModel::get_input_type( $field ) === 'date';
|
|
|
| if ( $this->_args['format'] || ! $target_is_date_field ) {
|
| $format = $this->get_format();
|
| } else {
|
|
|
| list( $format, $divider ) = $field['dateFormat'] ? array_pad( explode( '_', $field['dateFormat'] ), 2, 'slash' ) : array( 'mdy', 'slash' );
|
| $dividers = array(
|
| 'slash' => '/',
|
| 'dot' => '.',
|
| 'dash' => '-',
|
| );
|
|
|
| $format = str_replace( 'y', 'Y', $format );
|
| $divider = $dividers[ $divider ];
|
| $format = implode( $divider, str_split( $format ) );
|
|
|
| }
|
|
|
| if ( $this->_args['modifier'] ) {
|
|
|
| $modifier = $this->_args['modifier'];
|
|
|
| if ( is_array( $modifier ) ) {
|
| $key = sprintf( 'input_%s', str_replace( '.', '_', $modifier['inputId'] ) );
|
| $modifier_field = GFAPI::get_field( $field->formId, (int) $modifier['inputId'] );
|
| $number_format = $modifier_field->numberFormat ? $modifier_field->numberFormat : 'currency';
|
|
|
|
|
| $value = gf_apply_filters( array( 'gwpd_get_field_value', $this->_args['form_id'], $modifier['inputId'] ), GFCommon::clean_number( rgpost( $key ), $number_format ), $modifier['inputId'] );
|
| $modifier = ! rgblank( $value ) ? sprintf( str_replace( '{0}', '%d', $modifier['modifier'] ), $value ) : false;
|
| }
|
|
|
| if ( $modifier ) {
|
| $timestamp = strtotime( $modifier, $timestamp );
|
| }
|
| }
|
|
|
| if ( $this->_args['min_date'] ) {
|
| $min_timestamp = strtotime( $this->_args['min_date'] ) ? strtotime( $this->_args['min_date'] ) : $this->_args['min_date'];
|
| if ( $min_timestamp > $timestamp ) {
|
| $timestamp = $min_timestamp;
|
| }
|
| }
|
|
|
| if ( $field->get_input_type() === 'time' ) {
|
|
|
| $hour = (int) date( 'G', $timestamp );
|
| $minute = date( 'i', $timestamp );
|
| $ampm = 'AM';
|
| if ( $field->timeFormat === '12' ) {
|
| if ( $hour > 12 ) {
|
| $hour -= 12;
|
| $ampm = 'PM';
|
| } elseif ( $hour === 0 ) {
|
| $hour = 12;
|
| }
|
| }
|
|
|
|
|
| $date = "{$hour}:{$minute} {$ampm}";
|
| } elseif ( $this->_args['enable_i18n'] ) {
|
| $date = strftime( $format, $timestamp );
|
| } else {
|
| $date = date( $format, $timestamp );
|
| }
|
|
|
| return $date;
|
| }
|
|
|
| public function get_format( $should_convert = null ) {
|
|
|
| if ( $should_convert === null ) {
|
| $should_convert = $this->_args['enable_i18n'];
|
| }
|
|
|
| $format = ! $this->_args['format'] ? 'Y-m-d' : $this->_args['format'];
|
| if ( $should_convert ) {
|
| $format = $this->date_format_to( $format, 'strf' );
|
| }
|
|
|
| return $format;
|
| }
|
|
|
| public function load_form_script( $form ) {
|
|
|
| if ( $this->is_applicable_form( $form ) && ! has_action( 'wp_footer', array( __CLASS__, 'output_script' ) ) ) {
|
| add_action( 'wp_footer', array( __CLASS__, 'output_script' ), 21 );
|
| add_action( 'gform_preview_footer', array( __CLASS__, 'output_script' ), 21 );
|
| }
|
|
|
| return $form;
|
| }
|
|
|
| public static function output_script() {
|
| ?>
|
|
|
| <script type="text/javascript">
|
|
|
| ( function( $ ) {
|
|
|
| window.GWPopulateDate = function( args ) {
|
|
|
| var self = this;
|
|
|
|
|
| for( prop in args ) {
|
| if( args.hasOwnProperty( prop ) ) {
|
| self[ prop ] = args[ prop ];
|
| }
|
| }
|
|
|
| self.init = function() {
|
|
|
| self.$sourceInputs = GWDates.getFieldInputs( self.sourceFieldId, self.formId );
|
|
|
| self.$sourceInputs.change( function() {
|
| self.populateDate( self.sourceFieldId, self.targetFieldId, self.getModifier(), self.format );
|
| } );
|
|
|
|
|
| $( document ).on( 'gppa_updated_batch_fields', function ( e, formId, updatedFieldIDs ) {
|
| for ( var i = 0, max = updatedFieldIDs.length; i < max; i ++ ) {
|
| if ( self.sourceFieldId === parseInt( updatedFieldIDs[i] ) ) {
|
| self.populateDate( self.sourceFieldId, self.targetFieldId, self.getModifier(), self.format );
|
| }
|
| }
|
| } );
|
|
|
| if( typeof self.modifier == 'object' ) {
|
| self.$modifierInputs = self.getInputs( self.modifier.inputId );
|
| self.$modifierInputs.change( function() {
|
| self.populateDate( self.sourceFieldId, self.targetFieldId, self.getModifier(), self.format );
|
| } );
|
| }
|
|
|
| $( document ).bind( 'gform_post_conditional_logic', function( event, formId, fields ) {
|
| if( formId == self.formId ) {
|
| self.populateDate( self.sourceFieldId, self.targetFieldId, self.getModifier(), self.format );
|
| }
|
| } );
|
|
|
| self.populateDate( self.sourceFieldId, self.targetFieldId, self.getModifier(), self.format );
|
|
|
| };
|
|
|
| self.populateDate = function( sourceFieldId, targetFieldId, modifier, format ) {
|
|
|
| var timestamp = GWDates.getFieldTimestamp( sourceFieldId, self.formId, undefined, self.utcOffset );
|
| if( timestamp === 0 ) {
|
| return;
|
| }
|
|
|
| var date = new Date( timestamp ),
|
| newDate = modifier ? new Date( GWPopulateDate.strtotime( modifier, date.getTime() / 1000 ) * 1000 ) : date;
|
|
|
| GWDates.populateDate( targetFieldId, self.formId, newDate.getTime(), format );
|
|
|
| };
|
|
|
| self.getModifier = function() {
|
|
|
| if( typeof self.modifier != 'object' ) {
|
| return self.modifier;
|
| }
|
|
|
| switch( self.modifier.type ) {
|
| case 'field':
|
| var inputId = self.modifier.inputId,
|
| value = self.getFieldValue( inputId ),
|
| modifier = value !== '' ? self.modifier.modifier.gformFormat( value ) : false;
|
| break;
|
| }
|
|
|
| return modifier;
|
| };
|
|
|
| self.getFieldValue = function( inputId ) {
|
|
|
| var $input = self.getInputs( inputId ),
|
| value = self.getCleanNumber( $input.val(), gformExtractFieldId( inputId ), self.formId );
|
|
|
| value = gform.applyFilters( 'gwpd_get_field_value', value, $input, inputId );
|
|
|
| if ( ! value || isNaN( value ) ) {
|
| value = 0;
|
| }
|
|
|
| return value;
|
| };
|
|
|
|
|
|
|
|
|
|
|
| self.getCleanNumber = function( value, fieldId, formId ) {
|
| if (typeof value === 'undefined') {
|
| return value;
|
| }
|
|
|
| var numberFormat = gf_get_field_number_format( fieldId, formId );
|
| var decimalSep = gformGetDecimalSeparator( numberFormat ? numberFormat : 'currency' );
|
| if ( decimalSep === ',' ) {
|
| value = value.replace( '.', '' ).replace( ',', '.' );
|
| } else {
|
| value = value.replace( ',', '' );
|
| }
|
| return parseFloat( value );
|
| }
|
|
|
| self.getInputs = function( inputId ) {
|
|
|
| var fieldId = gformExtractFieldId( inputId ),
|
| inputIndex = gformExtractInputIndex( inputId ),
|
| id = inputIndex !== fieldId ? '#input_{0}_{1}' : '#input_{0}_{1}_{2}',
|
| $input = $( id.gformFormat( self.formId, fieldId, inputIndex ) );
|
|
|
| return $input;
|
| };
|
|
|
| GWPopulateDate.strtotime = function( str, now ) {
|
| var reSpace = '[ \\t]+';
|
| var reSpaceOpt = '[ \\t]*';
|
| var reMeridian = '(?:([ap])\\.?m\\.?([\\t ]|$))';
|
| var reHour24 = '(2[0-4]|[01]?[0-9])';
|
| var reHour24lz = '([01][0-9]|2[0-4])';
|
| var reHour12 = '(0?[1-9]|1[0-2])';
|
| var reMinute = '([0-5]?[0-9])';
|
| var reMinutelz = '([0-5][0-9])';
|
| var reSecond = '(60|[0-5]?[0-9])';
|
| var reSecondlz = '(60|[0-5][0-9])';
|
| var reFrac = '(?:\\.([0-9]+))';
|
|
|
| var reDayfull = 'sunday|monday|tuesday|wednesday|thursday|friday|saturday';
|
| var reDayabbr = 'sun|mon|tue|wed|thu|fri|sat';
|
| var reDaytext = reDayfull + '|' + reDayabbr + '|weekdays?';
|
|
|
| var reReltextnumber = 'first|second|third|fourth|fifth|sixth|seventh|eighth?|ninth|tenth|eleventh|twelfth';
|
| var reReltexttext = 'next|last|previous|this';
|
| var reReltextunit = '(?:second|sec|minute|min|hour|day|fortnight|forthnight|month|year)s?|weeks|' + reDaytext;
|
|
|
| var reYear = '([0-9]{1,4})';
|
| var reYear2 = '([0-9]{2})';
|
| var reYear4 = '([0-9]{4})';
|
| var reYear4withSign = '([+-]?[0-9]{4})';
|
| var reMonth = '(1[0-2]|0?[0-9])';
|
| var reMonthlz = '(0[0-9]|1[0-2])';
|
| var reDay = '(?:(3[01]|[0-2]?[0-9])(?:st|nd|rd|th)?)';
|
| var reDaylz = '(0[0-9]|[1-2][0-9]|3[01])';
|
|
|
| var reMonthFull = 'january|february|march|april|may|june|july|august|september|october|november|december';
|
| var reMonthAbbr = 'jan|feb|mar|apr|may|jun|jul|aug|sept?|oct|nov|dec';
|
| var reMonthroman = 'i[vx]|vi{0,3}|xi{0,2}|i{1,3}';
|
| var reMonthText = '(' + reMonthFull + '|' + reMonthAbbr + '|' + reMonthroman + ')';
|
|
|
| var reTzCorrection = '((?:GMT)?([+-])' + reHour24 + ':?' + reMinute + '?)';
|
| var reDayOfYear = '(00[1-9]|0[1-9][0-9]|[12][0-9][0-9]|3[0-5][0-9]|36[0-6])';
|
| var reWeekOfYear = '(0[1-9]|[1-4][0-9]|5[0-3])';
|
|
|
| var reDateNoYear = reMonthText + '[ .\\t-]*' + reDay + '[,.stndrh\\t ]*';
|
|
|
| function processMeridian(hour, meridian) {
|
| meridian = meridian && meridian.toLowerCase();
|
|
|
| switch (meridian) {
|
| case 'a':
|
| hour += hour === 12 ? -12 : 0;
|
| break;
|
| case 'p':
|
| hour += hour !== 12 ? 12 : 0;
|
| break;
|
| }
|
|
|
| return hour;
|
| }
|
|
|
| function processYear(yearStr) {
|
| var year = +yearStr;
|
|
|
| if (yearStr.length < 4 && year < 100) {
|
| year += year < 70 ? 2000 : 1900;
|
| }
|
|
|
| return year;
|
| }
|
|
|
| function lookupMonth(monthStr) {
|
| return {
|
| jan: 0,
|
| january: 0,
|
| i: 0,
|
| feb: 1,
|
| february: 1,
|
| ii: 1,
|
| mar: 2,
|
| march: 2,
|
| iii: 2,
|
| apr: 3,
|
| april: 3,
|
| iv: 3,
|
| may: 4,
|
| v: 4,
|
| jun: 5,
|
| june: 5,
|
| vi: 5,
|
| jul: 6,
|
| july: 6,
|
| vii: 6,
|
| aug: 7,
|
| august: 7,
|
| viii: 7,
|
| sep: 8,
|
| sept: 8,
|
| september: 8,
|
| ix: 8,
|
| oct: 9,
|
| october: 9,
|
| x: 9,
|
| nov: 10,
|
| november: 10,
|
| xi: 10,
|
| dec: 11,
|
| december: 11,
|
| xii: 11
|
| }[monthStr.toLowerCase()];
|
| }
|
|
|
| function lookupWeekday(dayStr) {
|
| var desiredSundayNumber = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
|
| var dayNumbers = {
|
| mon: 1,
|
| monday: 1,
|
| tue: 2,
|
| tuesday: 2,
|
| wed: 3,
|
| wednesday: 3,
|
| thu: 4,
|
| thursday: 4,
|
| fri: 5,
|
| friday: 5,
|
| sat: 6,
|
| saturday: 6,
|
| sun: 0,
|
| sunday: 0
|
| };
|
|
|
| return dayNumbers[dayStr.toLowerCase()] || desiredSundayNumber;
|
| }
|
|
|
| function lookupRelative(relText) {
|
| var relativeNumbers = {
|
| last: -1,
|
| previous: -1,
|
| this: 0,
|
| first: 1,
|
| next: 1,
|
| second: 2,
|
| third: 3,
|
| fourth: 4,
|
| fifth: 5,
|
| sixth: 6,
|
| seventh: 7,
|
| eight: 8,
|
| eighth: 8,
|
| ninth: 9,
|
| tenth: 10,
|
| eleventh: 11,
|
| twelfth: 12
|
| };
|
|
|
| var relativeBehavior = {
|
| this: 1
|
| };
|
|
|
| var relTextLower = relText.toLowerCase();
|
|
|
| return {
|
| amount: relativeNumbers[relTextLower],
|
| behavior: relativeBehavior[relTextLower] || 0
|
| };
|
| }
|
|
|
| function processTzCorrection(tzOffset, oldValue) {
|
| var reTzCorrectionLoose = /(?:GMT)?([+-])(\d+)(:?)(\d{0,2})/i;
|
| tzOffset = tzOffset && tzOffset.match(reTzCorrectionLoose);
|
|
|
| if (!tzOffset) {
|
| return oldValue;
|
| }
|
|
|
| var sign = tzOffset[1] === '-' ? 1 : -1;
|
| var hours = +tzOffset[2];
|
| var minutes = +tzOffset[4];
|
|
|
| if (!tzOffset[4] && !tzOffset[3]) {
|
| minutes = Math.floor(hours % 100);
|
| hours = Math.floor(hours / 100);
|
| }
|
|
|
| return sign * (hours * 60 + minutes);
|
| }
|
|
|
| var formats = {
|
| yesterday: {
|
| regex: /^yesterday/i,
|
| name: 'yesterday',
|
| callback: function callback() {
|
| this.rd -= 1;
|
| return this.resetTime();
|
| }
|
| },
|
|
|
| now: {
|
| regex: /^now/i,
|
| name: 'now'
|
|
|
| },
|
|
|
| noon: {
|
| regex: /^noon/i,
|
| name: 'noon',
|
| callback: function callback() {
|
| return this.resetTime() && this.time(12, 0, 0, 0);
|
| }
|
| },
|
|
|
| midnightOrToday: {
|
| regex: /^(midnight|today)/i,
|
| name: 'midnight | today',
|
| callback: function callback() {
|
| return this.resetTime();
|
| }
|
| },
|
|
|
| tomorrow: {
|
| regex: /^tomorrow/i,
|
| name: 'tomorrow',
|
| callback: function callback() {
|
| this.rd += 1;
|
| return this.resetTime();
|
| }
|
| },
|
|
|
| timestamp: {
|
| regex: /^@(-?\d+)/i,
|
| name: 'timestamp',
|
| callback: function callback(match, timestamp) {
|
| this.rs += +timestamp;
|
| this.y = 1970;
|
| this.m = 0;
|
| this.d = 1;
|
| this.dates = 0;
|
|
|
| return this.resetTime() && this.zone(0);
|
| }
|
| },
|
|
|
| firstOrLastDay: {
|
| regex: /^(first|last) day of/i,
|
| name: 'firstdayof | lastdayof',
|
| callback: function callback(match, day) {
|
| if (day.toLowerCase() === 'first') {
|
| this.firstOrLastDayOfMonth = 1;
|
| } else {
|
| this.firstOrLastDayOfMonth = -1;
|
| }
|
| }
|
| },
|
|
|
| backOrFrontOf: {
|
| regex: RegExp('^(back|front) of ' + reHour24 + reSpaceOpt + reMeridian + '?', 'i'),
|
| name: 'backof | frontof',
|
| callback: function callback(match, side, hours, meridian) {
|
| var back = side.toLowerCase() === 'back';
|
| var hour = +hours;
|
| var minute = 15;
|
|
|
| if (!back) {
|
| hour -= 1;
|
| minute = 45;
|
| }
|
|
|
| hour = processMeridian(hour, meridian);
|
|
|
| return this.resetTime() && this.time(hour, minute, 0, 0);
|
| }
|
| },
|
|
|
| weekdayOf: {
|
| regex: RegExp('^(' + reReltextnumber + '|' + reReltexttext + ')' + reSpace + '(' + reDayfull + '|' + reDayabbr + ')' + reSpace + 'of', 'i'),
|
| name: 'weekdayof'
|
|
|
| },
|
|
|
| mssqltime: {
|
| regex: RegExp('^' + reHour12 + ':' + reMinutelz + ':' + reSecondlz + '[:.]([0-9]+)' + reMeridian, 'i'),
|
| name: 'mssqltime',
|
| callback: function callback(match, hour, minute, second, frac, meridian) {
|
| return this.time(processMeridian(+hour, meridian), +minute, +second, +frac.substr(0, 3));
|
| }
|
| },
|
|
|
| timeLong12: {
|
| regex: RegExp('^' + reHour12 + '[:.]' + reMinute + '[:.]' + reSecondlz + reSpaceOpt + reMeridian, 'i'),
|
| name: 'timelong12',
|
| callback: function callback(match, hour, minute, second, meridian) {
|
| return this.time(processMeridian(+hour, meridian), +minute, +second, 0);
|
| }
|
| },
|
|
|
| timeShort12: {
|
| regex: RegExp('^' + reHour12 + '[:.]' + reMinutelz + reSpaceOpt + reMeridian, 'i'),
|
| name: 'timeshort12',
|
| callback: function callback(match, hour, minute, meridian) {
|
| return this.time(processMeridian(+hour, meridian), +minute, 0, 0);
|
| }
|
| },
|
|
|
| timeTiny12: {
|
| regex: RegExp('^' + reHour12 + reSpaceOpt + reMeridian, 'i'),
|
| name: 'timetiny12',
|
| callback: function callback(match, hour, meridian) {
|
| return this.time(processMeridian(+hour, meridian), 0, 0, 0);
|
| }
|
| },
|
|
|
| soap: {
|
| regex: RegExp('^' + reYear4 + '-' + reMonthlz + '-' + reDaylz + 'T' + reHour24lz + ':' + reMinutelz + ':' + reSecondlz + reFrac + reTzCorrection + '?', 'i'),
|
| name: 'soap',
|
| callback: function callback(match, year, month, day, hour, minute, second, frac, tzCorrection) {
|
| return this.ymd(+year, month - 1, +day) && this.time(+hour, +minute, +second, +frac.substr(0, 3)) && this.zone(processTzCorrection(tzCorrection));
|
| }
|
| },
|
|
|
| wddx: {
|
| regex: RegExp('^' + reYear4 + '-' + reMonth + '-' + reDay + 'T' + reHour24 + ':' + reMinute + ':' + reSecond),
|
| name: 'wddx',
|
| callback: function callback(match, year, month, day, hour, minute, second) {
|
| return this.ymd(+year, month - 1, +day) && this.time(+hour, +minute, +second, 0);
|
| }
|
| },
|
|
|
| exif: {
|
| regex: RegExp('^' + reYear4 + ':' + reMonthlz + ':' + reDaylz + ' ' + reHour24lz + ':' + reMinutelz + ':' + reSecondlz, 'i'),
|
| name: 'exif',
|
| callback: function callback(match, year, month, day, hour, minute, second) {
|
| return this.ymd(+year, month - 1, +day) && this.time(+hour, +minute, +second, 0);
|
| }
|
| },
|
|
|
| xmlRpc: {
|
| regex: RegExp('^' + reYear4 + reMonthlz + reDaylz + 'T' + reHour24 + ':' + reMinutelz + ':' + reSecondlz),
|
| name: 'xmlrpc',
|
| callback: function callback(match, year, month, day, hour, minute, second) {
|
| return this.ymd(+year, month - 1, +day) && this.time(+hour, +minute, +second, 0);
|
| }
|
| },
|
|
|
| xmlRpcNoColon: {
|
| regex: RegExp('^' + reYear4 + reMonthlz + reDaylz + '[Tt]' + reHour24 + reMinutelz + reSecondlz),
|
| name: 'xmlrpcnocolon',
|
| callback: function callback(match, year, month, day, hour, minute, second) {
|
| return this.ymd(+year, month - 1, +day) && this.time(+hour, +minute, +second, 0);
|
| }
|
| },
|
|
|
| clf: {
|
| regex: RegExp('^' + reDay + '/(' + reMonthAbbr + ')/' + reYear4 + ':' + reHour24lz + ':' + reMinutelz + ':' + reSecondlz + reSpace + reTzCorrection, 'i'),
|
| name: 'clf',
|
| callback: function callback(match, day, month, year, hour, minute, second, tzCorrection) {
|
| return this.ymd(+year, lookupMonth(month), +day) && this.time(+hour, +minute, +second, 0) && this.zone(processTzCorrection(tzCorrection));
|
| }
|
| },
|
|
|
| iso8601long: {
|
| regex: RegExp('^t?' + reHour24 + '[:.]' + reMinute + '[:.]' + reSecond + reFrac, 'i'),
|
| name: 'iso8601long',
|
| callback: function callback(match, hour, minute, second, frac) {
|
| return this.time(+hour, +minute, +second, +frac.substr(0, 3));
|
| }
|
| },
|
|
|
| dateTextual: {
|
| regex: RegExp('^' + reMonthText + '[ .\\t-]*' + reDay + '[,.stndrh\\t ]+' + reYear, 'i'),
|
| name: 'datetextual',
|
| callback: function callback(match, month, day, year) {
|
| return this.ymd(processYear(year), lookupMonth(month), +day);
|
| }
|
| },
|
|
|
| pointedDate4: {
|
| regex: RegExp('^' + reDay + '[.\\t-]' + reMonth + '[.-]' + reYear4),
|
| name: 'pointeddate4',
|
| callback: function callback(match, day, month, year) {
|
| return this.ymd(+year, month - 1, +day);
|
| }
|
| },
|
|
|
| pointedDate2: {
|
| regex: RegExp('^' + reDay + '[.\\t]' + reMonth + '\\.' + reYear2),
|
| name: 'pointeddate2',
|
| callback: function callback(match, day, month, year) {
|
| return this.ymd(processYear(year), month - 1, +day);
|
| }
|
| },
|
|
|
| timeLong24: {
|
| regex: RegExp('^t?' + reHour24 + '[:.]' + reMinute + '[:.]' + reSecond),
|
| name: 'timelong24',
|
| callback: function callback(match, hour, minute, second) {
|
| return this.time(+hour, +minute, +second, 0);
|
| }
|
| },
|
|
|
| dateNoColon: {
|
| regex: RegExp('^' + reYear4 + reMonthlz + reDaylz),
|
| name: 'datenocolon',
|
| callback: function callback(match, year, month, day) {
|
| return this.ymd(+year, month - 1, +day);
|
| }
|
| },
|
|
|
| pgydotd: {
|
| regex: RegExp('^' + reYear4 + '\\.?' + reDayOfYear),
|
| name: 'pgydotd',
|
| callback: function callback(match, year, day) {
|
| return this.ymd(+year, 0, +day);
|
| }
|
| },
|
|
|
| timeShort24: {
|
| regex: RegExp('^t?' + reHour24 + '[:.]' + reMinute, 'i'),
|
| name: 'timeshort24',
|
| callback: function callback(match, hour, minute) {
|
| return this.time(+hour, +minute, 0, 0);
|
| }
|
| },
|
|
|
| iso8601noColon: {
|
| regex: RegExp('^t?' + reHour24lz + reMinutelz + reSecondlz, 'i'),
|
| name: 'iso8601nocolon',
|
| callback: function callback(match, hour, minute, second) {
|
| return this.time(+hour, +minute, +second, 0);
|
| }
|
| },
|
|
|
| iso8601dateSlash: {
|
|
|
|
|
|
|
| regex: RegExp('^' + reYear4 + '/' + reMonthlz + '/' + reDaylz + '/'),
|
| name: 'iso8601dateslash',
|
| callback: function callback(match, year, month, day) {
|
| return this.ymd(+year, month - 1, +day);
|
| }
|
| },
|
|
|
| dateSlash: {
|
| regex: RegExp('^' + reYear4 + '/' + reMonth + '/' + reDay),
|
| name: 'dateslash',
|
| callback: function callback(match, year, month, day) {
|
| return this.ymd(+year, month - 1, +day);
|
| }
|
| },
|
|
|
| american: {
|
| regex: RegExp('^' + reMonth + '/' + reDay + '/' + reYear),
|
| name: 'american',
|
| callback: function callback(match, month, day, year) {
|
| return this.ymd(processYear(year), month - 1, +day);
|
| }
|
| },
|
|
|
| americanShort: {
|
| regex: RegExp('^' + reMonth + '/' + reDay),
|
| name: 'americanshort',
|
| callback: function callback(match, month, day) {
|
| return this.ymd(this.y, month - 1, +day);
|
| }
|
| },
|
|
|
| gnuDateShortOrIso8601date2: {
|
|
|
| regex: RegExp('^' + reYear + '-' + reMonth + '-' + reDay),
|
| name: 'gnudateshort | iso8601date2',
|
| callback: function callback(match, year, month, day) {
|
| return this.ymd(processYear(year), month - 1, +day);
|
| }
|
| },
|
|
|
| iso8601date4: {
|
| regex: RegExp('^' + reYear4withSign + '-' + reMonthlz + '-' + reDaylz),
|
| name: 'iso8601date4',
|
| callback: function callback(match, year, month, day) {
|
| return this.ymd(+year, month - 1, +day);
|
| }
|
| },
|
|
|
| gnuNoColon: {
|
| regex: RegExp('^t?' + reHour24lz + reMinutelz, 'i'),
|
| name: 'gnunocolon',
|
| callback: function callback(match, hour, minute) {
|
|
|
|
|
| switch (this.times) {
|
| case 0:
|
| return this.time(+hour, +minute, 0, this.f);
|
| case 1:
|
| this.y = hour * 100 + +minute;
|
| this.times++;
|
|
|
| return true;
|
| default:
|
| return false;
|
| }
|
| }
|
| },
|
|
|
| gnuDateShorter: {
|
| regex: RegExp('^' + reYear4 + '-' + reMonth),
|
| name: 'gnudateshorter',
|
| callback: function callback(match, year, month) {
|
| return this.ymd(+year, month - 1, 1);
|
| }
|
| },
|
|
|
| pgTextReverse: {
|
|
|
|
|
| regex: RegExp('^' + '(\\d{3,4}|[4-9]\\d|3[2-9])-(' + reMonthAbbr + ')-' + reDaylz, 'i'),
|
| name: 'pgtextreverse',
|
| callback: function callback(match, year, month, day) {
|
| return this.ymd(processYear(year), lookupMonth(month), +day);
|
| }
|
| },
|
|
|
| dateFull: {
|
| regex: RegExp('^' + reDay + '[ \\t.-]*' + reMonthText + '[ \\t.-]*' + reYear, 'i'),
|
| name: 'datefull',
|
| callback: function callback(match, day, month, year) {
|
| return this.ymd(processYear(year), lookupMonth(month), +day);
|
| }
|
| },
|
|
|
| dateNoDay: {
|
| regex: RegExp('^' + reMonthText + '[ .\\t-]*' + reYear4, 'i'),
|
| name: 'datenoday',
|
| callback: function callback(match, month, year) {
|
| return this.ymd(+year, lookupMonth(month), 1);
|
| }
|
| },
|
|
|
| dateNoDayRev: {
|
| regex: RegExp('^' + reYear4 + '[ .\\t-]*' + reMonthText, 'i'),
|
| name: 'datenodayrev',
|
| callback: function callback(match, year, month) {
|
| return this.ymd(+year, lookupMonth(month), 1);
|
| }
|
| },
|
|
|
| pgTextShort: {
|
| regex: RegExp('^(' + reMonthAbbr + ')-' + reDaylz + '-' + reYear, 'i'),
|
| name: 'pgtextshort',
|
| callback: function callback(match, month, day, year) {
|
| return this.ymd(processYear(year), lookupMonth(month), +day);
|
| }
|
| },
|
|
|
| dateNoYear: {
|
| regex: RegExp('^' + reDateNoYear, 'i'),
|
| name: 'datenoyear',
|
| callback: function callback(match, month, day) {
|
| return this.ymd(this.y, lookupMonth(month), +day);
|
| }
|
| },
|
|
|
| dateNoYearRev: {
|
| regex: RegExp('^' + reDay + '[ .\\t-]*' + reMonthText, 'i'),
|
| name: 'datenoyearrev',
|
| callback: function callback(match, day, month) {
|
| return this.ymd(this.y, lookupMonth(month), +day);
|
| }
|
| },
|
|
|
| isoWeekDay: {
|
| regex: RegExp('^' + reYear4 + '-?W' + reWeekOfYear + '(?:-?([0-7]))?'),
|
| name: 'isoweekday | isoweek',
|
| callback: function callback(match, year, week, day) {
|
| day = day ? +day : 1;
|
|
|
| if (!this.ymd(+year, 0, 1)) {
|
| return false;
|
| }
|
|
|
|
|
| var dayOfWeek = new Date(this.y, this.m, this.d).getDay();
|
|
|
|
|
| dayOfWeek = 0 - (dayOfWeek > 4 ? dayOfWeek - 7 : dayOfWeek);
|
|
|
| this.rd += dayOfWeek + (week - 1) * 7 + day;
|
| }
|
| },
|
|
|
| relativeText: {
|
| regex: RegExp('^(' + reReltextnumber + '|' + reReltexttext + ')' + reSpace + '(' + reReltextunit + ')', 'i'),
|
| name: 'relativetext',
|
| callback: function callback(match, relValue, relUnit) {
|
|
|
|
|
| var _lookupRelative = lookupRelative(relValue),
|
| amount = _lookupRelative.amount,
|
| behavior = _lookupRelative.behavior;
|
|
|
| switch (relUnit.toLowerCase()) {
|
| case 'sec':
|
| case 'secs':
|
| case 'second':
|
| case 'seconds':
|
| this.rs += amount;
|
| break;
|
| case 'min':
|
| case 'mins':
|
| case 'minute':
|
| case 'minutes':
|
| this.ri += amount;
|
| break;
|
| case 'hour':
|
| case 'hours':
|
| this.rh += amount;
|
| break;
|
| case 'day':
|
| case 'days':
|
| this.rd += amount;
|
| break;
|
| case 'fortnight':
|
| case 'fortnights':
|
| case 'forthnight':
|
| case 'forthnights':
|
| this.rd += amount * 14;
|
| break;
|
| case 'week':
|
| case 'weeks':
|
| this.rd += amount * 7;
|
| break;
|
| case 'month':
|
| case 'months':
|
| this.rm += amount;
|
| break;
|
| case 'year':
|
| case 'years':
|
| this.ry += amount;
|
| break;
|
| case 'mon':case 'monday':
|
| case 'tue':case 'tuesday':
|
| case 'wed':case 'wednesday':
|
| case 'thu':case 'thursday':
|
| case 'fri':case 'friday':
|
| case 'sat':case 'saturday':
|
| case 'sun':case 'sunday':
|
| this.resetTime();
|
| this.weekday = lookupWeekday(relUnit, 7);
|
| this.weekdayBehavior = 1;
|
| this.rd += (amount > 0 ? amount - 1 : amount) * 7;
|
| break;
|
| case 'weekday':
|
| case 'weekdays':
|
|
|
| break;
|
| }
|
| }
|
| },
|
|
|
| relative: {
|
| regex: RegExp('^([+-]*)[ \\t]*(\\d+)' + reSpaceOpt + '(' + reReltextunit + '|week)', 'i'),
|
| name: 'relative',
|
| callback: function callback(match, signs, relValue, relUnit) {
|
| var minuses = signs.replace(/[^-]/g, '').length;
|
|
|
| var amount = +relValue * Math.pow(-1, minuses);
|
|
|
| switch (relUnit.toLowerCase()) {
|
| case 'sec':
|
| case 'secs':
|
| case 'second':
|
| case 'seconds':
|
| this.rs += amount;
|
| break;
|
| case 'min':
|
| case 'mins':
|
| case 'minute':
|
| case 'minutes':
|
| this.ri += amount;
|
| break;
|
| case 'hour':
|
| case 'hours':
|
| this.rh += amount;
|
| break;
|
| case 'day':
|
| case 'days':
|
| this.rd += amount;
|
| break;
|
| case 'fortnight':
|
| case 'fortnights':
|
| case 'forthnight':
|
| case 'forthnights':
|
| this.rd += amount * 14;
|
| break;
|
| case 'week':
|
| case 'weeks':
|
| this.rd += amount * 7;
|
| break;
|
| case 'month':
|
| case 'months':
|
| this.rm += amount;
|
| break;
|
| case 'year':
|
| case 'years':
|
| this.ry += amount;
|
| break;
|
| case 'mon':case 'monday':
|
| case 'tue':case 'tuesday':
|
| case 'wed':case 'wednesday':
|
| case 'thu':case 'thursday':
|
| case 'fri':case 'friday':
|
| case 'sat':case 'saturday':
|
| case 'sun':case 'sunday':
|
| this.resetTime();
|
| this.weekday = lookupWeekday(relUnit, 7);
|
| this.weekdayBehavior = 1;
|
| this.rd += (amount > 0 ? amount - 1 : amount) * 7;
|
| break;
|
| case 'weekday':
|
| case 'weekdays':
|
| this.rwd += amount;
|
| break;
|
| }
|
| }
|
| },
|
|
|
| dayText: {
|
| regex: RegExp('^(' + reDaytext + ')', 'i'),
|
| name: 'daytext',
|
| callback: function callback(match, dayText) {
|
| this.resetTime();
|
| this.weekday = lookupWeekday(dayText, 0);
|
|
|
| if (this.weekdayBehavior !== 2) {
|
| this.weekdayBehavior = 1;
|
| }
|
| }
|
| },
|
|
|
| relativeTextWeek: {
|
| regex: RegExp('^(' + reReltexttext + ')' + reSpace + 'week', 'i'),
|
| name: 'relativetextweek',
|
| callback: function callback(match, relText) {
|
| this.weekdayBehavior = 2;
|
|
|
| switch (relText.toLowerCase()) {
|
| case 'this':
|
| this.rd += 0;
|
| break;
|
| case 'next':
|
| this.rd += 7;
|
| break;
|
| case 'last':
|
| case 'previous':
|
| this.rd -= 7;
|
| break;
|
| }
|
|
|
| if (isNaN(this.weekday)) {
|
| this.weekday = 1;
|
| }
|
| }
|
| },
|
|
|
| monthFullOrMonthAbbr: {
|
| regex: RegExp('^(' + reMonthFull + '|' + reMonthAbbr + ')', 'i'),
|
| name: 'monthfull | monthabbr',
|
| callback: function callback(match, month) {
|
| return this.ymd(this.y, lookupMonth(month), this.d);
|
| }
|
| },
|
|
|
| tzCorrection: {
|
| regex: RegExp('^' + reTzCorrection, 'i'),
|
| name: 'tzcorrection',
|
| callback: function callback(tzCorrection) {
|
| return this.zone(processTzCorrection(tzCorrection));
|
| }
|
| },
|
|
|
| ago: {
|
| regex: /^ago/i,
|
| name: 'ago',
|
| callback: function callback() {
|
| this.ry = -this.ry;
|
| this.rm = -this.rm;
|
| this.rd = -this.rd;
|
| this.rwd = -this.rwd;
|
| this.rh = -this.rh;
|
| this.ri = -this.ri;
|
| this.rs = -this.rs;
|
| this.rf = -this.rf;
|
| }
|
| },
|
|
|
| year4: {
|
| regex: RegExp('^' + reYear4),
|
| name: 'year4',
|
| callback: function callback(match, year) {
|
| this.y = +year;
|
| return true;
|
| }
|
| },
|
|
|
| whitespace: {
|
| regex: /^[ .,\t]+/,
|
| name: 'whitespace'
|
|
|
| },
|
|
|
| dateShortWithTimeLong: {
|
| regex: RegExp('^' + reDateNoYear + 't?' + reHour24 + '[:.]' + reMinute + '[:.]' + reSecond, 'i'),
|
| name: 'dateshortwithtimelong',
|
| callback: function callback(match, month, day, hour, minute, second) {
|
| return this.ymd(this.y, lookupMonth(month), +day) && this.time(+hour, +minute, +second, 0);
|
| }
|
| },
|
|
|
| dateShortWithTimeLong12: {
|
| regex: RegExp('^' + reDateNoYear + reHour12 + '[:.]' + reMinute + '[:.]' + reSecondlz + reSpaceOpt + reMeridian, 'i'),
|
| name: 'dateshortwithtimelong12',
|
| callback: function callback(match, month, day, hour, minute, second, meridian) {
|
| return this.ymd(this.y, lookupMonth(month), +day) && this.time(processMeridian(+hour, meridian), +minute, +second, 0);
|
| }
|
| },
|
|
|
| dateShortWithTimeShort: {
|
| regex: RegExp('^' + reDateNoYear + 't?' + reHour24 + '[:.]' + reMinute, 'i'),
|
| name: 'dateshortwithtimeshort',
|
| callback: function callback(match, month, day, hour, minute) {
|
| return this.ymd(this.y, lookupMonth(month), +day) && this.time(+hour, +minute, 0, 0);
|
| }
|
| },
|
|
|
| dateShortWithTimeShort12: {
|
| regex: RegExp('^' + reDateNoYear + reHour12 + '[:.]' + reMinutelz + reSpaceOpt + reMeridian, 'i'),
|
| name: 'dateshortwithtimeshort12',
|
| callback: function callback(match, month, day, hour, minute, meridian) {
|
| return this.ymd(this.y, lookupMonth(month), +day) && this.time(processMeridian(+hour, meridian), +minute, 0, 0);
|
| }
|
| }
|
| };
|
|
|
| var resultProto = {
|
|
|
| y: NaN,
|
| m: NaN,
|
| d: NaN,
|
|
|
| h: NaN,
|
| i: NaN,
|
| s: NaN,
|
| f: NaN,
|
|
|
|
|
| ry: 0,
|
| rm: 0,
|
| rd: 0,
|
| rwd: 0,
|
| rh: 0,
|
| ri: 0,
|
| rs: 0,
|
| rf: 0,
|
|
|
|
|
| weekday: NaN,
|
| weekdayBehavior: 0,
|
|
|
|
|
|
|
| firstOrLastDayOfMonth: 0,
|
|
|
|
|
| z: NaN,
|
|
|
|
|
| dates: 0,
|
| times: 0,
|
| zones: 0,
|
|
|
|
|
| ymd: function ymd(y, m, d) {
|
| if (this.dates > 0) {
|
| return false;
|
| }
|
|
|
| this.dates++;
|
| this.y = y;
|
| this.m = m;
|
| this.d = d;
|
| return true;
|
| },
|
| time: function time(h, i, s, f) {
|
| if (this.times > 0) {
|
| return false;
|
| }
|
|
|
| this.times++;
|
| this.h = h;
|
| this.i = i;
|
| this.s = s;
|
| this.f = f;
|
|
|
| return true;
|
| },
|
| resetTime: function resetTime() {
|
| this.h = 0;
|
| this.i = 0;
|
| this.s = 0;
|
| this.f = 0;
|
| this.times = 0;
|
|
|
| return true;
|
| },
|
| zone: function zone(minutes) {
|
| if (this.zones <= 1) {
|
| this.zones++;
|
| this.z = minutes;
|
| return true;
|
| }
|
|
|
| return false;
|
| },
|
| toDate: function toDate(relativeTo) {
|
| if (this.dates && !this.times) {
|
| this.h = this.i = this.s = this.f = 0;
|
| }
|
|
|
|
|
| if (isNaN(this.y)) {
|
| this.y = relativeTo.getFullYear();
|
| }
|
|
|
| if (isNaN(this.m)) {
|
| this.m = relativeTo.getMonth();
|
| }
|
|
|
| if (isNaN(this.d)) {
|
| this.d = relativeTo.getDate();
|
| }
|
|
|
| if (isNaN(this.h)) {
|
| this.h = relativeTo.getHours();
|
| }
|
|
|
| if (isNaN(this.i)) {
|
| this.i = relativeTo.getMinutes();
|
| }
|
|
|
| if (isNaN(this.s)) {
|
| this.s = relativeTo.getSeconds();
|
| }
|
|
|
| if (isNaN(this.f)) {
|
| this.f = relativeTo.getMilliseconds();
|
| }
|
|
|
|
|
| switch (this.firstOrLastDayOfMonth) {
|
| case 1:
|
| this.d = 1;
|
| break;
|
| case -1:
|
| this.d = 0;
|
| this.m += 1;
|
| break;
|
| }
|
|
|
| if (!isNaN(this.weekday)) {
|
| var date = new Date(relativeTo.getTime());
|
| date.setFullYear(this.y, this.m, this.d);
|
| date.setHours(this.h, this.i, this.s, this.f);
|
|
|
| var dow = date.getDay();
|
|
|
| if (this.weekdayBehavior === 2) {
|
|
|
| if (dow === 0 && this.weekday !== 0) {
|
| this.weekday = -6;
|
| }
|
|
|
|
|
| if (this.weekday === 0 && dow !== 0) {
|
| this.weekday = 7;
|
| }
|
|
|
| this.d -= dow;
|
| this.d += this.weekday;
|
| } else {
|
| var diff = this.weekday - dow;
|
|
|
|
|
| if (this.rd < 0 && diff < 0 || this.rd >= 0 && diff <= -this.weekdayBehavior) {
|
| diff += 7;
|
| }
|
|
|
| if (this.weekday >= 0) {
|
| this.d += diff;
|
| } else {
|
| this.d -= 7 - (Math.abs(this.weekday) - dow);
|
| }
|
|
|
| this.weekday = NaN;
|
| }
|
| }
|
|
|
|
|
| this.y += this.ry;
|
| this.m += this.rm;
|
| this.d += this.rd;
|
|
|
| this.h += this.rh;
|
| this.i += this.ri;
|
| this.s += this.rs;
|
| this.f += this.rf;
|
|
|
| this.ry = this.rm = this.rd = 0;
|
| this.rh = this.ri = this.rs = this.rf = 0;
|
|
|
| var result = new Date(relativeTo.getTime());
|
|
|
|
|
| result.setFullYear(this.y, this.m, this.d);
|
| result.setHours(this.h, this.i, this.s, this.f);
|
|
|
| if ( this.rwd ) {
|
|
|
|
|
|
|
|
|
| var mod = this.rwd < 0 ? -1 : 1;
|
| var i = Math.abs( this.rwd );
|
| while ( i > 0 ) {
|
| result.setDate( result.getDate() + mod );
|
| var currentDay = result.getDay();
|
| if ( currentDay !== 6 && currentDay !== 0 ) {
|
| i--;
|
| }
|
| }
|
| }
|
|
|
|
|
|
|
|
|
|
|
|
|
| switch (this.firstOrLastDayOfMonth) {
|
| case 1:
|
| result.setDate(1);
|
| break;
|
| case -1:
|
| result.setMonth(result.getMonth() + 1, 0);
|
| break;
|
| }
|
|
|
|
|
| if (!isNaN(this.z) && result.getTimezoneOffset() !== this.z) {
|
| result.setUTCFullYear(result.getFullYear(), result.getMonth(), result.getDate());
|
|
|
| result.setUTCHours(result.getHours(), result.getMinutes() + this.z, result.getSeconds(), result.getMilliseconds());
|
| }
|
|
|
| return result;
|
| }
|
| };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| if (now == null) {
|
| now = Math.floor(Date.now() / 1000);
|
| }
|
|
|
|
|
|
|
|
|
| var rules = [formats.yesterday, formats.now, formats.noon, formats.midnightOrToday, formats.tomorrow, formats.timestamp, formats.firstOrLastDay, formats.backOrFrontOf,
|
|
|
| formats.timeTiny12, formats.timeShort12, formats.timeLong12, formats.mssqltime, formats.timeShort24, formats.timeLong24, formats.iso8601long, formats.gnuNoColon, formats.iso8601noColon, formats.americanShort, formats.american, formats.iso8601date4, formats.iso8601dateSlash, formats.dateSlash, formats.gnuDateShortOrIso8601date2, formats.gnuDateShorter, formats.dateFull, formats.pointedDate4, formats.pointedDate2, formats.dateNoDay, formats.dateNoDayRev, formats.dateTextual, formats.dateNoYear, formats.dateNoYearRev, formats.dateNoColon, formats.xmlRpc, formats.xmlRpcNoColon, formats.soap, formats.wddx, formats.exif, formats.pgydotd, formats.isoWeekDay, formats.pgTextShort, formats.pgTextReverse, formats.clf, formats.year4, formats.ago, formats.dayText, formats.relativeTextWeek, formats.relativeText, formats.monthFullOrMonthAbbr, formats.tzCorrection, formats.dateShortWithTimeShort12, formats.dateShortWithTimeLong12, formats.dateShortWithTimeShort, formats.dateShortWithTimeLong, formats.relative, formats.whitespace];
|
|
|
| var result = Object.create(resultProto);
|
|
|
| while (str.length) {
|
| var longestMatch = null;
|
| var finalRule = null;
|
|
|
| for (var i = 0, l = rules.length; i < l; i++) {
|
| var format = rules[i];
|
|
|
| var match = str.match(format.regex);
|
|
|
| if (match) {
|
| if (!longestMatch || match[0].length > longestMatch[0].length) {
|
| longestMatch = match;
|
| finalRule = format;
|
| }
|
| }
|
| }
|
|
|
| if (!finalRule || finalRule.callback && finalRule.callback.apply(result, longestMatch) === false) {
|
| return false;
|
| }
|
|
|
| str = str.substr(longestMatch[0].length);
|
| finalRule = null;
|
| longestMatch = null;
|
| }
|
|
|
| return Math.floor(result.toDate(new Date(now * 1000)) / 1000);
|
| };
|
|
|
| self.init();
|
|
|
| };
|
|
|
| window.GWDates = {
|
|
|
| getFieldTimestamp: function( dateTimeFieldId, formId, $inputs, utcOffset ) {
|
|
|
| var field;
|
|
|
| if( typeof dateTimeFieldId == 'object' ) {
|
| field = dateTimeFieldId;
|
| } else {
|
| field = GWDates.getFieldPropsByCSS( dateTimeFieldId, formId );
|
| }
|
|
|
| var isVisible = window['gf_check_field_rule'] ? gf_check_field_rule( formId, field.id, true, '' ) == 'show' : true,
|
| $inputs = typeof $inputs == 'undefined' ? GWDates.getFieldInputs( field.id, formId ) : $inputs,
|
| value = 0;
|
|
|
| if( $inputs.length <= 0 || ! isVisible ) {
|
| return value;
|
| }
|
|
|
| var allInputsFilled = true;
|
| $inputs.each( function( i, input ) {
|
| if( ! $( input ).val() ) {
|
| allInputsFilled = false;
|
| }
|
| } );
|
|
|
| if( ! allInputsFilled ) {
|
| return value;
|
| }
|
|
|
| switch( field.type ) {
|
|
|
| case 'date':
|
|
|
| var formatBits = field.dateFormat.split( '_' ),
|
| mdy = formatBits[0],
|
| separator = formatBits[1] ? formatBits[1] : 'slash',
|
| sepChars = { slash: '/', dot: '.', dash: '-' },
|
| sepChar = sepChars[ separator ];
|
|
|
| switch( field.dateType ) {
|
| case 'datefield':
|
| case 'datedropdown':
|
| var month = $inputs.eq( mdy.indexOf( 'm' ) ).val(),
|
| day = $inputs.eq( mdy.indexOf( 'd' ) ).val(),
|
| year = $inputs.eq( mdy.indexOf( 'y' ) ).val(),
|
| missingData = ! month || ! day || ! year,
|
| datetime = missingData ? false : new Date( year, month - 1, day, 0, 0, 0, 0 );
|
| break;
|
| case 'datepicker':
|
| var dateArr = $inputs.eq( 0 ).val().split( sepChar ),
|
| month = dateArr[ mdy.indexOf( 'm' )],
|
| day = dateArr[ mdy.indexOf( 'd' ) ],
|
| year = dateArr[ mdy.indexOf( 'y' ) ],
|
| missingData = ! month || ! day || ! year,
|
| datetime = missingData ? false : new Date( year, month - 1, day, 0, 0, 0, 0 );
|
| datetime = new Date( year, month - 1, day, 0, 0, 0, 0 );
|
| break;
|
| default:
|
| break;
|
| }
|
|
|
|
|
|
|
|
|
|
|
| var now = new Date();
|
|
|
|
|
| now = new Date( now.getTime() + ( now.getTimezoneOffset() * 60000 ) + ( utcOffset * 60 * 60000 ) );
|
|
|
| if (datetime.getDate() == now.getDate() && datetime.getMonth() == now.getMonth() && datetime.getFullYear() == now.getFullYear()) {
|
| datetime.setHours(now.getHours());
|
| datetime.setMinutes(now.getMinutes());
|
| datetime.setSeconds(now.getSeconds());
|
| }
|
|
|
| var timestamp = datetime === false ? false : datetime.getTime();
|
|
|
| break;
|
|
|
| case 'time':
|
|
|
| var hour = parseInt( $inputs.eq( 0 ).val() ),
|
| min = parseInt( $inputs.eq( 1 ).val() ),
|
| ampm = $inputs.eq( 2 ).val(),
|
| missingData = isNaN( hour ) || isNaN( min ),
|
| datetime = missingData ? false : new Date();
|
|
|
| if ( $inputs.eq( 2 ).length ) {
|
| hours = hour;
|
|
|
| if (ampm.toLowerCase() === 'am') {
|
| hours += hour === 12 ? -12 : 0;
|
| } else {
|
| hours += hour !== 12 ? 12 : 0;
|
| }
|
|
|
| datetime.setHours( hours );
|
| } else {
|
| datetime.setHours( hour );
|
| }
|
|
|
| datetime.setMinutes( min );
|
|
|
| timestamp = datetime.getTime();
|
|
|
| break;
|
|
|
| }
|
|
|
| return timestamp;
|
| },
|
|
|
| getFieldPropsByCSS: function( fieldId, formId ) {
|
|
|
| var $field = $( '#field_' + formId + '_' + fieldId ),
|
| classes = $field.attr( 'class' ),
|
| field = { id: fieldId, type: null };
|
|
|
| if( ! classes ) {
|
| return field;
|
| }
|
|
|
| var cssClasses = $field.attr( 'class' ).split( /\s+/ );
|
|
|
| for( var i = 0; i < cssClasses.length; i++ ) {
|
| if( cssClasses[i].indexOf( 'gw-field-' ) != -1 ) {
|
|
|
| var classBits = cssClasses[i].split( '-' ),
|
| prop = classBits[2],
|
| value = classBits[3];
|
|
|
| field[prop] = value;
|
|
|
| }
|
| }
|
|
|
|
|
|
|
| return field;
|
| },
|
|
|
| populateDate: function( dateTimeFieldId, formId, timestamp, format ) {
|
|
|
| var field = GWDates.getFieldPropsByCSS( dateTimeFieldId, formId ),
|
| date = timestamp instanceof Date ? timestamp: new Date( timestamp ),
|
| isVisible = window['gf_check_field_rule'] ? gf_check_field_rule( formId, field.id, true, '' ) == 'show' : true,
|
| $inputs = typeof $inputs == 'undefined' ? $( '#field_' + formId + '_' + field.id ).find( 'input, select' ) : $inputs,
|
| oldValues = $inputs.val();
|
|
|
| if( $inputs.length <= 0 || ! isVisible ) {
|
| return false;
|
| }
|
|
|
| switch( field.type ) {
|
| case 'date':
|
|
|
| var formatBits = field.dateFormat.split( '_' ),
|
| mdy = formatBits[0],
|
| separator = formatBits[1] ? formatBits[1] : 'slash',
|
| sepChars = { slash: '/', dot: '.', dash: '-' },
|
| dateParts = {
|
| month: isNaN( date.getMonth() ) ? '' : date.getMonth() + 1,
|
| day: isNaN( date.getDate() ) ? '' : date.getDate(),
|
| year: isNaN( date.getFullYear() ) ? '' : date.getFullYear()
|
| };
|
|
|
| switch( field.dateType ) {
|
| case 'datefield':
|
| case 'datedropdown':
|
| $inputs.eq( mdy.indexOf( 'm' ) ).val( dateParts.month );
|
| $inputs.eq( mdy.indexOf( 'd' ) ).val( dateParts.day );
|
| $inputs.eq( mdy.indexOf( 'y' ) ).val( dateParts.year );
|
| break;
|
| case 'datepicker':
|
| var dateStr = ! dateParts.month ? '' : mdy.split( '' ).join( sepChars[ separator ] )
|
| .replace( 'm', GWDates.padDateOrMonth( dateParts.month ) )
|
| .replace( 'd', GWDates.padDateOrMonth( dateParts.day ) )
|
| .replace( 'y', dateParts.year );
|
| $inputs.val( dateStr );
|
| break;
|
| default:
|
| break;
|
| }
|
|
|
|
|
| if( oldValues !== $inputs.val() ) {
|
| $inputs.change();
|
| }
|
|
|
| break;
|
| case 'time':
|
| var hours = isNaN( date.getHours() ) ? '' : date.getHours(),
|
| minutes = isNaN( date.getMinutes() ) ? '' : date.getMinutes(),
|
| hasAMPM = $inputs.filter( 'select' ).length === 1,
|
| isPM = false;
|
|
|
| if ( hasAMPM ) {
|
| if ( hours === 0 ) {
|
| hours = 12;
|
| } else if ( hours > 12 ) {
|
| hours -= 12;
|
| isPM = true;
|
| } else if ( hours == 12 ) {
|
|
|
| isPM = true;
|
| }
|
| }
|
|
|
| $inputs.eq( 0 ).val( hours );
|
| $inputs.eq( 1 ).val( GWDates.padDateOrMonth( minutes ) );
|
|
|
| if ( hasAMPM ) {
|
| if ( isPM ) {
|
| $inputs.eq( 2 ).find( 'option:last' ).prop( 'selected', true );
|
| } else {
|
| $inputs.eq( 2 ).find( 'option:first' ).prop( 'selected', true );
|
| }
|
| }
|
|
|
|
|
| if( oldValues !== $inputs.val() ) {
|
| $inputs.change();
|
| }
|
|
|
| break;
|
| default:
|
|
|
| var mo = moment( timestamp ),
|
| value = mo.formatPHP( format );
|
|
|
| if( $inputs.val() != value ) {
|
| $inputs.val( value ).change();
|
| }
|
|
|
| break;
|
| }
|
|
|
| },
|
|
|
| getFieldInputs: function( fieldId, formId ) {
|
| return $( '#field_' + formId + '_' + fieldId ).find( 'input, select' ).not( '[type="hidden"]');
|
| },
|
|
|
| padDateOrMonth: function( num ) {
|
| return ( '0' + num ).slice( -2 );
|
| }
|
|
|
| }
|
|
|
| } )( jQuery );
|
|
|
| ( function ( m ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
| var formatMap = {
|
| d: 'DD',
|
| D: 'ddd',
|
| j: 'D',
|
| l: 'dddd',
|
| N: 'E',
|
| S: function () {
|
| return '[' + this.format('Do').replace(/\d*/g, '') + ']';
|
| },
|
| w: 'd',
|
| z: function () {
|
| return this.format('DDD') - 1;
|
| },
|
| W: 'W',
|
| F: 'MMMM',
|
| m: 'MM',
|
| M: 'MMM',
|
| n: 'M',
|
| t: function () {
|
| return this.daysInMonth();
|
| },
|
| L: function () {
|
| return this.isLeapYear() ? 1 : 0;
|
| },
|
| o: 'GGGG',
|
| Y: 'YYYY',
|
| y: 'YY',
|
| a: 'a',
|
| A: 'A',
|
| B: function () {
|
| var thisUTC = this.clone().utc(),
|
|
|
| swatch = ((thisUTC.hours() + 1) % 24) + (thisUTC.minutes() / 60) + (thisUTC.seconds() / 3600);
|
| return Math.floor(swatch * 1000 / 24);
|
| },
|
| g: 'h',
|
| G: 'H',
|
| h: 'hh',
|
| H: 'HH',
|
| i: 'mm',
|
| s: 'ss',
|
| u: '[u]',
|
| e: '[e]',
|
| I: function () {
|
| return this.isDST() ? 1 : 0;
|
| },
|
| O: 'ZZ',
|
| P: 'Z',
|
| T: '[T]',
|
| Z: function () {
|
| return parseInt(this.format('ZZ'), 10) * 36;
|
| },
|
| c: 'YYYY-MM-DD[T]HH:mm:ssZ',
|
| r: 'ddd, DD MMM YYYY HH:mm:ss ZZ',
|
| U: 'X'
|
| },
|
| formatEx = /[dDjlNSwzWFmMntLoYyaABgGhHisueIOPTZcrU]/g;
|
|
|
| moment.fn.formatPHP = function (format) {
|
| var that = this;
|
|
|
| return this.format(format.replace(formatEx, function (phpStr) {
|
| return typeof formatMap[phpStr] === 'function' ? formatMap[phpStr].call(that) : formatMap[phpStr];
|
| }));
|
| };
|
|
|
| }( moment ) );
|
|
|
| </script>
|
|
|
| <?php
|
|
|
| self::$is_script_output = true;
|
|
|
| }
|
|
|
| public function add_init_script( $form ) {
|
|
|
| if ( ! $this->is_applicable_form( $form ) ) {
|
| return;
|
| }
|
|
|
| $args = array(
|
| 'formId' => $this->_args['form_id'],
|
| 'targetFieldId' => $this->_args['target_field_id'],
|
| 'sourceFieldId' => $this->_args['source_field_id'],
|
| 'modifier' => $this->_args['modifier'],
|
| 'utcOffset' => $this->_args['utc_offset'],
|
|
|
| 'format' => $this->get_format( false ),
|
| );
|
|
|
| $script = 'new GWPopulateDate( ' . json_encode( $args ) . ' );';
|
| $slug = implode( '_', array_filter( array( 'gw_populate_date', $this->_args['form_id'], $this->_args['source_field_id'], $this->_args['target_field_id'], rgar( $this->_args['modifier'], 'inputId' ) ) ) );
|
|
|
| GFFormDisplay::add_init_script( $this->_args['form_id'], $slug, GFFormDisplay::ON_PAGE_RENDER, $script );
|
|
|
| }
|
|
|
| public function is_applicable_form( $form ) {
|
|
|
| $form_id = isset( $form['id'] ) ? $form['id'] : $form;
|
|
|
| return $form_id == $this->_args['form_id'];
|
| }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| function date_format_to( $format, $syntax ) {
|
|
|
| $strf_syntax = array(
|
|
|
| '%O',
|
| '%d',
|
| '%a',
|
| '%e',
|
| '%A',
|
| '%u',
|
| '%w',
|
| '%j',
|
|
|
| '%V',
|
|
|
| '%B',
|
| '%m',
|
| '%b',
|
| '%-m',
|
|
|
| '%G',
|
| '%Y',
|
| '%y',
|
|
|
| '%P',
|
| '%p',
|
| '%l',
|
| '%I',
|
| '%H',
|
| '%M',
|
| '%S',
|
|
|
| '%z',
|
| '%Z',
|
|
|
| '%s',
|
| );
|
|
|
|
|
| $date_syntax = array(
|
| 'S',
|
| 'd',
|
| 'D',
|
| 'j',
|
| 'l',
|
| 'N',
|
| 'w',
|
| 'z',
|
| 'W',
|
| 'F',
|
| 'm',
|
| 'M',
|
| 'n',
|
| 'o',
|
| 'Y',
|
| 'y',
|
| 'a',
|
| 'A',
|
| 'g',
|
| 'h',
|
| 'H',
|
| 'i',
|
| 's',
|
| 'O',
|
| 'T',
|
| 'U',
|
| );
|
|
|
| switch ( $syntax ) {
|
| case 'date':
|
| $from = $strf_syntax;
|
| $to = $date_syntax;
|
| break;
|
|
|
| case 'strf':
|
| $from = $date_syntax;
|
| $to = $strf_syntax;
|
| break;
|
|
|
| default:
|
| return false;
|
| }
|
|
|
| $pattern = array_map(
|
| function ( $s ) {
|
| return '/(?<!\\\\|\%)' . $s . '/';
|
| },
|
| $from
|
| );
|
|
|
| return preg_replace( $pattern, $to, $format );
|
| }
|
|
|
| }
|
|
|
|
|
| add_filter( 'gform_pre_render', function( $form ) {
|
|
|
| $prefix = 'gw-field-';
|
|
|
| foreach ( $form['fields'] as &$field ) {
|
|
|
| $classes = false;
|
|
|
| switch ( GFFormsModel::get_input_type( $field ) ) {
|
| case 'date':
|
| $classes = array(
|
| 'type' => sprintf( '%stype-%s', $prefix, $field->type ),
|
| 'date_type' => sprintf( '%sdateType-%s', $prefix, $field->dateType ),
|
| 'date_format' => sprintf( '%sdateFormat-%s', $prefix, $field->dateFormat ? $field->dateFormat : 'mdy' ),
|
| );
|
| break;
|
| case 'time':
|
| $classes = array(
|
| 'type' => sprintf( '%stype-%s', $prefix, $field->type ),
|
| 'time_format' => sprintf( '%stimeFormat-%s', $prefix, $field->timeFormat ? $field->timeFormat : 'mdy' ),
|
| );
|
| break;
|
| }
|
|
|
| if ( $classes ) {
|
| $current_classes = explode( ' ', $field->cssClass );
|
| $classes = array_unique( array_merge( $current_classes, $classes ), SORT_REGULAR );
|
| $field->cssClass .= ' ' . implode( ' ', $classes );
|
| }
|
| }
|
|
|
| return $form;
|
| } );
|
|
|
|
|
|
|
| new GW_Populate_Date( array(
|
| 'form_id' => 5,
|
| 'target_field_id' => 5,
|
| 'modifier' => '+90 days',
|
| ) );
|
| |
| |