Inheritance: System.Web.UI.WebControls.CompositeControl, IRockControlAdditionalRendering
        /// <summary>
        /// Creates the child controls.
        /// </summary>
        /// <returns></returns>
        public override Control[] CreateChildControls( Type entityType, FilterField filterControl )
        {
            AccountPicker accountPicker = new AccountPicker();
            accountPicker.AllowMultiSelect = true;
            accountPicker.ID = filterControl.ID + "_accountPicker";
            accountPicker.AddCssClass( "js-account-picker" );
            accountPicker.Label = "Accounts";
            filterControl.Controls.Add( accountPicker );

            SlidingDateRangePicker slidingDateRangePicker = new SlidingDateRangePicker();
            slidingDateRangePicker.ID = filterControl.ID + "_slidingDateRangePicker";
            slidingDateRangePicker.AddCssClass( "js-sliding-date-range" );
            slidingDateRangePicker.Label = "Date Range";
            slidingDateRangePicker.Help = "The date range of the transactions using the 'Sunday Date' of each transaction";
            slidingDateRangePicker.Required = true;
            filterControl.Controls.Add( slidingDateRangePicker );

            var controls = new Control[2] { accountPicker, slidingDateRangePicker };

            return controls;
        }
Example #2
0
        /// <summary>
        /// Gets the help HTML that explains usage of the SlidingDateRange picker with examples
        /// </summary>
        /// <param name="currentDateTime">The current date time.</param>
        /// <returns></returns>
        public static string GetHelpHtml( DateTime currentDateTime )
        {
            SlidingDateRangePicker helperPicker = new SlidingDateRangePicker();
            SlidingDateRangeType[] slidingDateRangeTypesForHelp = new SlidingDateRangeType[] { SlidingDateRangeType.Current, SlidingDateRangeType.Previous, SlidingDateRangeType.Last, SlidingDateRangeType.Next, SlidingDateRangeType.Upcoming };

            string helpHtml = @"

            <div class='slidingdaterange-help'>

            <p>A date range can either be a specific date range, or a sliding date range based on the current date and time.</p>
            <p>For a sliding date range, you can choose either <strong>current, previous, last, next, upcoming</strong> with a time period of <strong>hour, day, week, month, or year</strong>. Note that a week is Monday thru Sunday.</p>
            <br />
            <ul class=''>
            <li><strong>Current</strong> - the time period that the current date/time is in</li>
            <li><strong>Previous</strong> - the time period(s) prior to the current period (does not include the current time period). For example, to see the most recent weekend, select 'Previous 1 Week'</li>
            <li><strong>Last</strong> - the last X time period(s) including the current until today. For example, to see so far this current week and prior week, select 'Last 2 weeks'</li>
            <li><strong>Next</strong> - the next X time period(s) including the rest of the current period. For example, to see the rest of the current month and the next full month after, select 'Next 2 months'</li>
            <li><strong>Upcoming</strong> - the upcoming X time period(s) not including the current time period.</li>
            </ul>

            <h3>Preview of the sliding date ranges</h3>";

            foreach ( var slidingDateRangeType in slidingDateRangeTypesForHelp )
            {
                helperPicker.SlidingDateRangeMode = slidingDateRangeType;
                helperPicker.NumberOfTimeUnits = 2;
                StringBuilder sb = new StringBuilder();
                sb.AppendFormat( @"<h4>{0}</h4>", slidingDateRangeType.ConvertToString() );
                sb.AppendLine( "<ul>" );
                foreach ( var timeUnitType in Enum.GetValues( typeof( TimeUnitType ) ).OfType<TimeUnitType>() )
                {
                    helperPicker.TimeUnit = timeUnitType;
                    sb.AppendFormat( @"
                    <li>
                        <span class='slidingdaterange-help-key'>{0} {1}</span>
                        <span class='slidingdaterange-help-value'> - {2}</span>
                    </li>",
                          slidingDateRangeType != SlidingDateRangeType.Current ? helperPicker.NumberOfTimeUnits.ToString() : string.Empty,
                          helperPicker.TimeUnit.ConvertToString().PluralizeIf( slidingDateRangeType != SlidingDateRangeType.Current && helperPicker.NumberOfTimeUnits > 1 ),
                          SlidingDateRangePicker.CalculateDateRangeFromDelimitedValues( helperPicker.DelimitedValues ).ToStringAutomatic() );
                }
                sb.AppendLine( "</ul>" );

                helpHtml += sb.ToString();
            }

            helpHtml += @"
            </div>
            ";

            return helpHtml;
        }
Example #3
0
        /// <summary>
        /// Gets the filter value control.
        /// </summary>
        /// <param name="configurationValues">The configuration values.</param>
        /// <param name="id">The identifier.</param>
        /// <param name="required">if set to <c>true</c> [required].</param>
        /// <param name="filterMode">The filter mode.</param>
        /// <returns></returns>
        public override Control FilterValueControl( Dictionary<string, ConfigurationValue> configurationValues, string id, bool required, FilterMode filterMode )
        {
            var dateFiltersPanel = new Panel();
            dateFiltersPanel.ID = string.Format( "{0}_dtFilterControls", id );

            var datePickerPanel = new Panel();
            dateFiltersPanel.Controls.Add( datePickerPanel );

            var datePicker = new DatePicker();
            datePicker.ID = string.Format( "{0}_dtPicker", id );
            datePicker.DisplayCurrentOption = true;
            datePickerPanel.AddCssClass( "js-filter-control" );
            datePickerPanel.Controls.Add( datePicker );

            var slidingDateRangePicker = new SlidingDateRangePicker();
            slidingDateRangePicker.ID = string.Format( "{0}_dtSlidingDateRange", id );
            slidingDateRangePicker.AddCssClass("js-filter-control-between");
            slidingDateRangePicker.Label = string.Empty;
            slidingDateRangePicker.PreviewLocation = SlidingDateRangePicker.DateRangePreviewLocation.Right;
            dateFiltersPanel.Controls.Add( slidingDateRangePicker );

            return dateFiltersPanel;
        }
        /// <summary>
        /// Creates the control(s) necessary for prompting user for a new value
        /// </summary>
        /// <param name="configurationValues">The configuration values.</param>
        /// <param name="id"></param>
        /// <returns>
        /// The control
        /// </returns>
        public override Control EditControl( System.Collections.Generic.Dictionary<string, ConfigurationValue> configurationValues, string id )
        {
            var picker = new SlidingDateRangePicker { ID = id };
            if ( configurationValues != null && configurationValues.ContainsKey( ENABLED_SLIDING_DATE_RANGE_TYPES ) )
            {
                var selectedDateRangeTypes = configurationValues[ENABLED_SLIDING_DATE_RANGE_TYPES].Value.SplitDelimitedValues().Select( a => a.ConvertToEnum<SlidingDateRangePicker.SlidingDateRangeType>() );
                picker.EnabledSlidingDateRangeTypes = selectedDateRangeTypes.ToArray();
            }

            if ( configurationValues != null && configurationValues.ContainsKey( ENABLED_SLIDING_DATE_RANGE_UNITS ) )
            {
                var selectedDateRangeUnits = configurationValues[ENABLED_SLIDING_DATE_RANGE_UNITS].Value.SplitDelimitedValues().Select( a => a.ConvertToEnum<SlidingDateRangePicker.TimeUnitType>() );
                picker.EnabledSlidingDateRangeUnits = selectedDateRangeUnits.ToArray();
            }

            return picker;
        }
        /// <summary>
        /// Creates the child controls.
        /// </summary>
        /// <returns></returns>
        public override Control[] CreateChildControls( Type entityType, FilterField filterControl )
        {
            rp = new RegistrationTemplatePicker();
            rp.ID = filterControl.ID + "_rp";
            rp.Label = "RegistrationTemplate(s)";
            rp.CssClass = "js-group-picker";
            rp.AllowMultiSelect = true;
            rp.Help = "Select the registration templates that you want the registrants for. Leaving this blank will not restrict results to a registration template.";
            filterControl.Controls.Add( rp );

            cbIncludeInactiveRegistrationInstances = new RockCheckBox();
            cbIncludeInactiveRegistrationInstances.ID = filterControl.ID + "_cbIncludeInactiveRegistrationInstances";
            cbIncludeInactiveRegistrationInstances.Text = "Include Inactive Registration Instances";
            cbIncludeInactiveRegistrationInstances.CssClass = "js-include-inactive-groups";
            cbIncludeInactiveRegistrationInstances.AutoPostBack = true;
            filterControl.Controls.Add( cbIncludeInactiveRegistrationInstances );

            PanelWidget pwAdvanced = new PanelWidget();
            filterControl.Controls.Add( pwAdvanced );
            pwAdvanced.ID = filterControl.ID + "_pwAttributes";
            pwAdvanced.Title = "Advanced Filters";
            pwAdvanced.CssClass = "advanced-panel";

            SlidingDateRangePicker registeredOnDateRangePicker = new SlidingDateRangePicker();
            registeredOnDateRangePicker.ID = pwAdvanced.ID + "_addedOnDateRangePicker";
            registeredOnDateRangePicker.AddCssClass( "js-sliding-date-range" );
            registeredOnDateRangePicker.Label = "Date Registered:";
            registeredOnDateRangePicker.Help = "Select the date range that the person was registered. Leaving this blank will not restrict results to a date range.";
            pwAdvanced.Controls.Add( registeredOnDateRangePicker );

            return new Control[4] { rp, cbIncludeInactiveRegistrationInstances, registeredOnDateRangePicker, pwAdvanced };
        }
        /// <summary>
        /// Formats the selection.
        /// </summary>
        /// <param name="entityType">Type of the entity.</param>
        /// <param name="selection">The selection.</param>
        /// <returns></returns>
        public override string FormatSelection( Type entityType, string selection )
        {
            string result = "Registrant";
            string[] selectionValues = selection.Split( '|' );
            if ( selectionValues.Length >= 1 )
            {
                var rockContext = new RockContext();
                var registrationTemplateGuids = selectionValues[0].Split( ',' ).AsGuidList();
                var registrationTemplates = new RegistrationTemplateService( rockContext ).GetByGuids( registrationTemplateGuids );

                SlidingDateRangePicker fakeSlidingDateRangePicker = null;

                bool includeInactiveRegistrationInstances = false;
                if ( selectionValues.Length >= 2 )
                {
                    includeInactiveRegistrationInstances = selectionValues[1].AsBooleanOrNull() ?? false;

                    if ( selectionValues.Length >= 3 )
                    {
                        fakeSlidingDateRangePicker = new SlidingDateRangePicker();

                        // convert comma delimited to pipe
                        fakeSlidingDateRangePicker.DelimitedValues = selectionValues[2].Replace( ',', '|' );
                    }
                }

                if ( registrationTemplates != null )
                {
                    result = string.Format( registrationTemplates.Count() > 0 ? "In Registration Templates: {0}" : "In a Registration", registrationTemplates.Select( a => a.Name ).ToList().AsDelimited( ", ", " or " ) );

                    if ( includeInactiveRegistrationInstances )
                    {
                        result += ", including inactive registration instances";
                    }

                    if ( fakeSlidingDateRangePicker != null )
                    {
                        result += string.Format( ", registered in Date Range: {0}", SlidingDateRangePicker.FormatDelimitedValues( fakeSlidingDateRangePicker.DelimitedValues ) );
                    }
                }
            }

            return result;
        }
        /// <summary>
        /// Creates the child controls.
        /// </summary>
        /// <returns></returns>
        public override Control[] CreateChildControls( System.Web.UI.Control parentControl )
        {
            var comparisonControl = ComparisonHelper.ComparisonControl( ComparisonType.LessThan | ComparisonType.GreaterThanOrEqualTo | ComparisonType.EqualTo );
            comparisonControl.ID = parentControl.ID + "_0";
            parentControl.Controls.Add( comparisonControl );

            var globalAttributes = Rock.Web.Cache.GlobalAttributesCache.Read();

            NumberBox numberBoxAmount = new NumberBox();
            numberBoxAmount.PrependText = globalAttributes.GetValue( "CurrencySymbol" ) ?? "$";
            numberBoxAmount.NumberType = ValidationDataType.Currency;
            numberBoxAmount.ID = parentControl.ID + "_1";
            numberBoxAmount.Label = "Amount";

            parentControl.Controls.Add( numberBoxAmount );

            AccountPicker accountPicker = new AccountPicker();
            accountPicker.AllowMultiSelect = true;
            accountPicker.ID = parentControl.ID + "_accountPicker";
            accountPicker.AddCssClass( "js-account-picker" );
            accountPicker.Label = "Accounts";
            parentControl.Controls.Add( accountPicker );

            SlidingDateRangePicker slidingDateRangePicker = new SlidingDateRangePicker();
            slidingDateRangePicker.ID = parentControl.ID + "_slidingDateRangePicker";
            slidingDateRangePicker.AddCssClass( "js-sliding-date-range" );
            slidingDateRangePicker.Label = "Date Range";
            slidingDateRangePicker.Help = "The date range of the transactions using the transaction date of each transaction";
            slidingDateRangePicker.Required = true;
            parentControl.Controls.Add( slidingDateRangePicker );

            RockCheckBox cbCombineGiving = new RockCheckBox();
            cbCombineGiving.ID = parentControl.ID + "_cbCombineGiving";
            cbCombineGiving.Label = "Combine Giving";
            cbCombineGiving.CssClass = "js-combine-giving";
            cbCombineGiving.Help = "Combine individuals in the same giving group when calculating totals and reporting the list of individuals.";
            parentControl.Controls.Add( cbCombineGiving );

            var controls = new Control[5] { comparisonControl, numberBoxAmount, accountPicker, slidingDateRangePicker, cbCombineGiving };

            SetSelection( controls, string.Format( "{0}||||||", ComparisonType.GreaterThanOrEqualTo.ConvertToInt().ToString() ) );

            return controls;
        }
Example #8
0
        /// <summary>
        /// Formats the selection for the InGroupFilter/NotInGroupFilter based on if we are in "Not" mode
        /// </summary>
        /// <param name="selection">The selection.</param>
        /// <param name="not">if set to <c>true</c> [not].</param>
        /// <returns></returns>
        public virtual string GroupFilterFormatSelection( string selection, bool not )
        {
            string result = "Group Member";
            string[] selectionValues = selection.Split( '|' );
            if ( selectionValues.Length >= 2 )
            {
                var rockContext = new RockContext();
                var groupGuids = selectionValues[0].Split( ',' ).AsGuidList();
                var groups = new GroupService( rockContext ).GetByGuids( groupGuids );

                var groupTypeRoleGuidList = selectionValues[1].Split( new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries ).Select( a => a.AsGuid() ).ToList();

                var groupTypeRoles = new GroupTypeRoleService( rockContext ).Queryable().Where( a => groupTypeRoleGuidList.Contains( a.Guid ) ).ToList();

                SlidingDateRangePicker fakeSlidingDateRangePicker = null;

                bool includeChildGroups = false;
                bool includeChildGroupsPlusDescendants = false;
                bool includeChildGroupsIncludeSelected = false;
                bool includeInactiveGroups = false;
                if ( selectionValues.Length >= 3 )
                {
                    includeChildGroups = selectionValues[2].AsBooleanOrNull() ?? false;
                    if ( selectionValues.Length >= 6 )
                    {
                        includeChildGroupsIncludeSelected = selectionValues[4].AsBooleanOrNull() ?? false;
                        includeChildGroupsPlusDescendants = selectionValues[5].AsBooleanOrNull() ?? false;
                    }

                    if ( selectionValues.Length >= 7 )
                    {
                        includeInactiveGroups = selectionValues[6].AsBooleanOrNull() ?? false;
                    }

                    if ( selectionValues.Length >= 8 )
                    {
                        fakeSlidingDateRangePicker = new SlidingDateRangePicker();

                        // convert comma delimited to pipe
                        fakeSlidingDateRangePicker.DelimitedValues = selectionValues[7].Replace( ',', '|' );
                    }
                }

                GroupMemberStatus? groupMemberStatus = null;
                if ( selectionValues.Length >= 4 )
                {
                    groupMemberStatus = selectionValues[3].ConvertToEnumOrNull<GroupMemberStatus>();
                }

                if ( groups != null )
                {
                    result = string.Format( not ? "Not in groups: {0}" : "In groups: {0}", groups.Select( a => a.Name ).ToList().AsDelimited( ", ", " or " ) );
                    if ( includeChildGroups )
                    {
                        if ( includeChildGroupsPlusDescendants )
                        {
                            result += " or descendant groups";
                        }
                        else
                        {
                            result += " or child groups";
                        }

                        if ( includeInactiveGroups )
                        {
                            result += ", including inactive groups";
                        }

                        if ( !includeChildGroupsIncludeSelected )
                        {
                            result += ", not including selected groups";
                        }

                    }

                    if ( groupTypeRoles.Count() > 0 )
                    {
                        result += string.Format( ", with role(s): {0}", groupTypeRoles.Select( a => string.Format( "{0} ({1})", a.Name, a.GroupType.Name ) ).ToList().AsDelimited( "," ) );
                    }

                    if ( groupMemberStatus.HasValue )
                    {
                        result += string.Format( ", with member status: {0}", groupMemberStatus.ConvertToString() );
                    }

                    if ( fakeSlidingDateRangePicker != null )
                    {
                        result += string.Format( ", added to group in Date Range: {0}", SlidingDateRangePicker.FormatDelimitedValues( fakeSlidingDateRangePicker.DelimitedValues ) );
                    }
                }
            }

            return result;
        }
Example #9
0
        /// <summary>
        /// Creates the child controls.
        /// </summary>
        /// <returns></returns>
        public override Control[] CreateChildControls( Type entityType, FilterField filterControl )
        {
            gp = new GroupPicker();
            gp.ID = filterControl.ID + "_gp";
            gp.Label = "Group(s)";
            gp.SelectItem += gp_SelectItem;
            gp.CssClass = "js-group-picker";
            gp.AllowMultiSelect = true;
            filterControl.Controls.Add( gp );

            cbChildGroups = new RockCheckBox();
            cbChildGroups.ID = filterControl.ID + "_cbChildsGroups";
            cbChildGroups.Text = "Include Child Group(s)";
            cbChildGroups.CssClass = "js-include-child-groups";
            cbChildGroups.AutoPostBack = true;
            cbChildGroups.CheckedChanged += gp_SelectItem;
            filterControl.Controls.Add( cbChildGroups );

            cbIncludeSelectedGroup = new RockCheckBox();
            cbIncludeSelectedGroup.ID = filterControl.ID + "_cbIncludeSelectedGroup";
            cbIncludeSelectedGroup.Text = "Include Selected Group(s)";
            cbIncludeSelectedGroup.CssClass = "js-include-selected-groups";
            cbIncludeSelectedGroup.AutoPostBack = true;
            cbIncludeSelectedGroup.CheckedChanged += gp_SelectItem;
            filterControl.Controls.Add( cbIncludeSelectedGroup );

            cbChildGroupsPlusDescendants = new RockCheckBox();
            cbChildGroupsPlusDescendants.ID = filterControl.ID + "_cbChildGroupsPlusDescendants";
            cbChildGroupsPlusDescendants.Text = "Include All Descendants(s)";
            cbChildGroupsPlusDescendants.CssClass = "js-include-child-groups-descendants";
            cbChildGroupsPlusDescendants.AutoPostBack = true;
            cbChildGroupsPlusDescendants.CheckedChanged += gp_SelectItem;
            filterControl.Controls.Add( cbChildGroupsPlusDescendants );

            cbIncludeInactiveGroups = new RockCheckBox();
            cbIncludeInactiveGroups.ID = filterControl.ID + "_cbIncludeInactiveGroups";
            cbIncludeInactiveGroups.Text = "Include Inactive Groups";
            cbIncludeInactiveGroups.CssClass = "js-include-inactive-groups";
            cbIncludeInactiveGroups.AutoPostBack = true;
            cbIncludeInactiveGroups.CheckedChanged += gp_SelectItem;
            filterControl.Controls.Add( cbIncludeInactiveGroups );

            cblRole = new RockCheckBoxList();
            cblRole.Label = "with Group Member Role(s) (optional)";
            cblRole.ID = filterControl.ID + "_cblRole";
            cblRole.CssClass = "js-roles";
            cblRole.Visible = false;
            filterControl.Controls.Add( cblRole );

            RockDropDownList ddlGroupMemberStatus = new RockDropDownList();
            ddlGroupMemberStatus.CssClass = "js-group-member-status";
            ddlGroupMemberStatus.ID = filterControl.ID + "_ddlGroupMemberStatus";
            ddlGroupMemberStatus.Label = "with Group Member Status";
            ddlGroupMemberStatus.Help = "Select a specific group member status to only include group members with that status. Leaving this blank will return all members.";
            ddlGroupMemberStatus.BindToEnum<GroupMemberStatus>( true );
            ddlGroupMemberStatus.SetValue( GroupMemberStatus.Active.ConvertToInt() );
            filterControl.Controls.Add( ddlGroupMemberStatus );

            PanelWidget pwAdvanced = new PanelWidget();
            filterControl.Controls.Add( pwAdvanced );
            pwAdvanced.ID = filterControl.ID + "_pwAttributes";
            pwAdvanced.Title = "Advanced Filters";
            pwAdvanced.CssClass = "advanced-panel";

            SlidingDateRangePicker addedOnDateRangePicker = new SlidingDateRangePicker();
            addedOnDateRangePicker.ID = pwAdvanced.ID + "_addedOnDateRangePicker";
            addedOnDateRangePicker.AddCssClass( "js-sliding-date-range" );
            addedOnDateRangePicker.Label = "Date Added:";
            addedOnDateRangePicker.Help = "Select the date range that the person was added to the group. Leaving this blank will not restrict results to a date range.";
            pwAdvanced.Controls.Add( addedOnDateRangePicker );

            return new Control[9] { gp, cbChildGroups, cbIncludeSelectedGroup, cbChildGroupsPlusDescendants, cblRole, ddlGroupMemberStatus, cbIncludeInactiveGroups, addedOnDateRangePicker, pwAdvanced };
        }
Example #10
0
        /// <summary>
        /// Creates the child controls.
        /// </summary>
        /// <returns></returns>
        public override Control[] CreateChildControls( Type entityType, FilterField filterControl )
        {
            var pGroupPicker = new GroupPicker();
            pGroupPicker.AllowMultiSelect = true;
            pGroupPicker.ID = filterControl.ID + "_pGroupPicker";
            pGroupPicker.AddCssClass( "js-group-picker" );
            filterControl.Controls.Add( pGroupPicker );

            var cbChildGroups = new RockCheckBox();
            cbChildGroups.ID = filterControl.ID + "_cbChildGroups";
            cbChildGroups.AddCssClass( "js-child-groups" );
            cbChildGroups.Text = "Include Child Groups";
            filterControl.Controls.Add( cbChildGroups );

            var ddlIntegerCompare = ComparisonHelper.ComparisonControl( ComparisonHelper.NumericFilterComparisonTypes );
            ddlIntegerCompare.Label = "Attendance Count";
            ddlIntegerCompare.ID = filterControl.ID + "_ddlIntegerCompare";
            ddlIntegerCompare.AddCssClass( "js-filter-compare" );
            filterControl.Controls.Add( ddlIntegerCompare );

            var tbAttendedCount = new RockTextBox();
            tbAttendedCount.ID = filterControl.ID + "_2";
            tbAttendedCount.Label = "&nbsp;"; // give it whitespace label so it lines up nicely
            tbAttendedCount.AddCssClass( "js-attended-count" );
            filterControl.Controls.Add( tbAttendedCount );

            var slidingDateRangePicker = new SlidingDateRangePicker();
            slidingDateRangePicker.Label = "Date Range";
            slidingDateRangePicker.ID = filterControl.ID + "_slidingDateRangePicker";
            slidingDateRangePicker.AddCssClass( "js-sliding-date-range" );
            filterControl.Controls.Add( slidingDateRangePicker );

            var controls = new Control[5] { pGroupPicker, cbChildGroups, ddlIntegerCompare, tbAttendedCount, slidingDateRangePicker };

            // convert pipe to comma delimited
            var defaultDelimitedValues = slidingDateRangePicker.DelimitedValues.Replace( "|", "," );
            var defaultCount = 4;

            // set the default values in case this is a newly added filter
            SetSelection(
                entityType,
                controls,
                string.Format( "{0}|{1}|{2}|{3}|false", string.Empty, ComparisonType.GreaterThanOrEqualTo.ConvertToInt().ToString(), defaultCount, defaultDelimitedValues ) );

            return controls;
        }
Example #11
0
        /// <summary>
        /// Formats the selection.
        /// </summary>
        /// <param name="entityType">Type of the entity.</param>
        /// <param name="selection">The selection.</param>
        /// <returns></returns>
        public override string FormatSelection( Type entityType, string selection )
        {
            string result = "Giving Amount";
            string[] selectionValues = selection.Split( '|' );

            if ( selectionValues.Length >= 4 )
            {
                ComparisonType comparisonType = selectionValues[0].ConvertToEnum<ComparisonType>( ComparisonType.GreaterThanOrEqualTo );
                decimal amount = selectionValues[1].AsDecimalOrNull() ?? 0.00M;
                string accountNames = string.Empty;
                if ( selectionValues.Length >= 5 )
                {
                    var accountGuids = selectionValues[4].Split( ',' ).Select( a => a.AsGuid() ).ToList();
                    accountNames = new FinancialAccountService( new RockContext() ).GetByGuids( accountGuids ).Select( a => a.Name ).ToList().AsDelimited( "," );
                }

                bool combineGiving = false;
                if ( selectionValues.Length >= 6 )
                {
                    combineGiving = selectionValues[5].AsBooleanOrNull() ?? false;
                }

                SlidingDateRangePicker fakeSlidingDateRangePicker = new SlidingDateRangePicker();

                if ( selectionValues.Length >= 7 )
                {
                    // convert comma delimited to pipe
                    fakeSlidingDateRangePicker.DelimitedValues = selectionValues[6].Replace( ',', '|' );
                }
                else
                {
                    // if converting from a previous version of the selection
                    var lowerValue = selectionValues[2].AsDateTime();
                    var upperValue = selectionValues[3].AsDateTime();

                    fakeSlidingDateRangePicker.SlidingDateRangeMode = SlidingDateRangePicker.SlidingDateRangeType.DateRange;
                    fakeSlidingDateRangePicker.SetDateRangeModeValue( new DateRange( lowerValue, upperValue ) );
                }

                result = string.Format(
                    "{4}Giving amount total {0} {1} {2}. Date Range: {3}",
                    comparisonType.ConvertToString().ToLower(),
                    amount.ToString( "C" ),
                    !string.IsNullOrWhiteSpace( accountNames ) ? " to accounts:" + accountNames : string.Empty,
                    SlidingDateRangePicker.FormatDelimitedValues( fakeSlidingDateRangePicker.DelimitedValues ),
                    combineGiving ? "Combined " : string.Empty);
            }

            return result;
        }
        /// <summary>
        /// Creates the child controls.
        /// </summary>
        /// <returns></returns>
        public override Control[] CreateChildControls( Type entityType, FilterField filterControl )
        {
            var gtpGroupType = new GroupTypePicker();
            gtpGroupType.ID = filterControl.ID + "_0";
            gtpGroupType.AddCssClass( "js-group-type" );
            filterControl.Controls.Add( gtpGroupType );

            gtpGroupType.UseGuidAsValue = true;
            gtpGroupType.GroupTypes = new GroupTypeService( new RockContext() ).Queryable().OrderBy(a => a.Name).ToList();

            var cbChildGroupTypes = new RockCheckBox();
            cbChildGroupTypes.ID = filterControl.ID + "_cbChildGroupTypes";
            cbChildGroupTypes.AddCssClass( "js-child-group-types" );
            cbChildGroupTypes.Text = "Include Child Group Types(s)";
            filterControl.Controls.Add( cbChildGroupTypes );

            var ddlIntegerCompare = ComparisonHelper.ComparisonControl( ComparisonHelper.NumericFilterComparisonTypes );
            ddlIntegerCompare.Label = "Attendance Count";
            ddlIntegerCompare.ID = filterControl.ID + "_ddlIntegerCompare";
            ddlIntegerCompare.AddCssClass( "js-filter-compare" );
            filterControl.Controls.Add( ddlIntegerCompare );

            var tbAttendedCount = new RockTextBox();
            tbAttendedCount.ID = filterControl.ID + "_2";
            tbAttendedCount.Label = "&nbsp;"; // give it whitespace label so it lines up nicely
            tbAttendedCount.AddCssClass( "js-attended-count" );
            filterControl.Controls.Add( tbAttendedCount );

            var slidingDateRangePicker = new SlidingDateRangePicker();
            slidingDateRangePicker.Label = "Date Range";
            slidingDateRangePicker.ID = filterControl.ID + "_slidingDateRangePicker";
            slidingDateRangePicker.AddCssClass( "js-sliding-date-range" );
            filterControl.Controls.Add( slidingDateRangePicker );

            var controls = new Control[5] { gtpGroupType, cbChildGroupTypes, ddlIntegerCompare, tbAttendedCount, slidingDateRangePicker };

            // convert pipe to comma delimited
            var defaultDelimitedValues = slidingDateRangePicker.DelimitedValues.Replace( "|", "," );
            var defaultCount = 4;

            // set the default values in case this is a newly added filter
            SetSelection(
                entityType,
                controls,
                string.Format( "{0}|{1}|{2}|{3}|false", gtpGroupType.Items.Count > 0 ? gtpGroupType.Items[0].Value : "0", ComparisonType.GreaterThanOrEqualTo.ConvertToInt().ToString(), defaultCount, defaultDelimitedValues ) );

            return controls;
        }
        /// <summary>
        /// Gets the expression.
        /// </summary>
        /// <param name="entityType">Type of the entity.</param>
        /// <param name="serviceInstance">The service instance.</param>
        /// <param name="parameterExpression">The parameter expression.</param>
        /// <param name="selection">The selection.</param>
        /// <returns></returns>
        public override Expression GetExpression( Type entityType, IService serviceInstance, ParameterExpression parameterExpression, string selection )
        {
            string[] options = selection.Split( '|' );
            if ( options.Length < 4 )
            {
                return null;
            }

            Guid groupTypeGuid = options[0].AsGuid();
            ComparisonType comparisonType = options[1].ConvertToEnum<ComparisonType>( ComparisonType.GreaterThanOrEqualTo );
            int? attended = options[2].AsIntegerOrNull();
            string slidingDelimitedValues;

            if ( options[3].AsIntegerOrNull().HasValue )
            {
                //// selection was from when it just simply a LastXWeeks instead of Sliding Date Range
                // Last X Weeks was treated as "LastXWeeks * 7" days, so we have to convert it to a SlidingDateRange of Days to keep consistent behavior
                int lastXWeeks = options[3].AsIntegerOrNull() ?? 1;
                var fakeSlidingDateRangePicker = new SlidingDateRangePicker();
                fakeSlidingDateRangePicker.SlidingDateRangeMode = SlidingDateRangePicker.SlidingDateRangeType.Last;
                fakeSlidingDateRangePicker.TimeUnit = SlidingDateRangePicker.TimeUnitType.Day;
                fakeSlidingDateRangePicker.NumberOfTimeUnits = lastXWeeks * 7;
                slidingDelimitedValues = fakeSlidingDateRangePicker.DelimitedValues;
            }
            else
            {
                slidingDelimitedValues = options[3].Replace( ',', '|' );
            }

            var dateRange = SlidingDateRangePicker.CalculateDateRangeFromDelimitedValues( slidingDelimitedValues );

            bool includeChildGroupTypes = options.Length >= 5 ? options[4].AsBooleanOrNull() ?? false : false;

            var groupTypeService = new GroupTypeService( new RockContext() );

            var groupType = groupTypeService.Get( groupTypeGuid );
            List<int> groupTypeIds = new List<int>();
            if ( groupType != null )
            {
                groupTypeIds.Add( groupType.Id );

                if ( includeChildGroupTypes )
                {
                    var childGroupTypes = groupTypeService.GetAllAssociatedDescendents( groupType.Guid );
                    if ( childGroupTypes.Any() )
                    {
                        groupTypeIds.AddRange( childGroupTypes.Select( a => a.Id ) );

                        // get rid of any duplicates
                        groupTypeIds = groupTypeIds.Distinct().ToList();
                    }
                }
            }

            var rockContext = serviceInstance.Context as RockContext;
            var attendanceQry = new AttendanceService( rockContext ).Queryable().Where( a => a.DidAttend.HasValue && a.DidAttend.Value );

            if ( dateRange.Start.HasValue )
            {
                var startDate = dateRange.Start.Value;
                attendanceQry = attendanceQry.Where( a => a.StartDateTime >= startDate );
            }

            if ( dateRange.End.HasValue )
            {
                var endDate = dateRange.End.Value;
                attendanceQry = attendanceQry.Where( a => a.StartDateTime < endDate );
            }

            if ( groupTypeIds.Count == 1 )
            {
                int groupTypeId = groupTypeIds[0];
                attendanceQry = attendanceQry.Where( a => a.Group.GroupTypeId == groupTypeId );
            }
            else if ( groupTypeIds.Count > 1 )
            {
                attendanceQry = attendanceQry.Where( a => groupTypeIds.Contains( a.Group.GroupTypeId ) );
            }
            else
            {
                // no group type selected, so return nothing
                return Expression.Constant( false );
            }

            var qry = new PersonService( rockContext ).Queryable()
                  .Where( p => attendanceQry.Where( xx => xx.PersonAlias.PersonId == p.Id ).Count() == attended );

            BinaryExpression compareEqualExpression = FilterExpressionExtractor.Extract<Rock.Model.Person>( qry, parameterExpression, "p" ) as BinaryExpression;
            BinaryExpression result = FilterExpressionExtractor.AlterComparisonType( comparisonType, compareEqualExpression, null );

            return result;
        }
        /// <summary>
        /// Formats the selection.
        /// </summary>
        /// <param name="entityType">Type of the entity.</param>
        /// <param name="selection">The selection.</param>
        /// <returns></returns>
        public override string FormatSelection( Type entityType, string selection )
        {
            string result = "First Contribution Date";
            string[] selectionValues = selection.Split( '|' );

            if ( selectionValues.Length >= 3 )
            {
                SlidingDateRangePicker fakeSlidingDateRangePicker = new SlidingDateRangePicker();

                if ( selectionValues.Length >= 4 )
                {
                    // convert comma delimited to pipe
                    fakeSlidingDateRangePicker.DelimitedValues = selectionValues[3].Replace( ',', '|' );
                }
                else
                {
                    // if converting from a previous version of the selection
                    var lowerValue = selectionValues[0].AsDateTime();
                    var upperValue = selectionValues[1].AsDateTime();

                    fakeSlidingDateRangePicker.SlidingDateRangeMode = SlidingDateRangePicker.SlidingDateRangeType.DateRange;
                    fakeSlidingDateRangePicker.SetDateRangeModeValue( new DateRange( lowerValue, upperValue ) );
                }

                string accountNames = string.Empty;
                var accountGuids = selectionValues[2].Split( ',' ).Select( a => a.AsGuid() ).ToList();
                accountNames = new FinancialAccountService( new RockContext() ).GetByGuids( accountGuids ).Select( a => a.Name ).ToList().AsDelimited( "," );

                result = string.Format(
                    "First contribution date{0}. Date Range: {1}",
                    !string.IsNullOrWhiteSpace( accountNames ) ? " to accounts:" + accountNames : string.Empty,
                    SlidingDateRangePicker.FormatDelimitedValues( fakeSlidingDateRangePicker.DelimitedValues )
                    )
                    ;
            }

            return result;
        }