/// <summary> /// Creates an HTML block editor. /// </summary> /// <param name="htmlBlockId"></param> /// <param name="idSetter"></param> /// <param name="mod"></param> /// <param name="setup">The setup object for the HTML block editor.</param> public HtmlBlockEditor(int?htmlBlockId, Action <int> idSetter, out HtmlBlockEditorModification mod, HtmlBlockEditorSetup setup = null) { setup = setup ?? new HtmlBlockEditorSetup(); this.mod = mod = new HtmlBlockEditorModification(htmlBlockId, htmlBlockId.HasValue ? HtmlBlockStatics.GetHtml(htmlBlockId.Value) : "", idSetter); var wysiwygEditor = new WysiwygHtmlEditor( mod.Html, true, (postBackValue, validator) => { this.mod.Html = postBackValue; setup.AdditionalValidationMethod?.Invoke(validator); }, setup: setup.WysiwygSetup); component = new DisplayableElement( context => { return(new DisplayableElementData( setup.DisplaySetup, () => new DisplayableElementLocalData("div"), classes: new ElementClass(CssElementCreator.CssClass), children: wysiwygEditor.PageComponent.ToCollection())); }); validation = wysiwygEditor.Validation; }
/// <summary> /// Creates a duration control. /// </summary> /// <param name="value"></param> /// <param name="allowEmpty"></param> /// <param name="setup">The setup object for the duration control.</param> /// <param name="validationMethod">The validation method. Pass null if you’re only using this control for page modification.</param> public DurationControl(TimeSpan?value, bool allowEmpty, DurationControlSetup setup = null, Action <TimeSpan?, Validator> validationMethod = null) { setup = setup ?? DurationControlSetup.Create(); var textControl = new TextControl( value.HasValue ? Math.Floor(value.Value.TotalHours).ToString("0000") + ":" + value.Value.Minutes.ToString("00") : "", allowEmpty, setup: setup.IsReadOnly ? TextControlSetup.CreateReadOnly(validationPredicate: setup.ValidationPredicate, validationErrorNotifier: setup.ValidationErrorNotifier) : TextControlSetup.Create( placeholder: "h:m", action: new SpecifiedValue <FormAction>(setup.Action), valueChangedAction: setup.ValueChangedAction, pageModificationValue: setup.PageModificationValue, validationPredicate: setup.ValidationPredicate, validationErrorNotifier: setup.ValidationErrorNotifier), validationMethod: validationMethod == null ? (Action <string, Validator>)null : (postBackValue, validator) => { if (tooLongOrInvalidCharacters(postBackValue)) { validator.NoteErrorAndAddMessage("Please enter a valid duration."); setup.ValidationErrorNotifier?.Invoke(); return; } var errorHandler = new ValidationErrorHandler("duration"); var validatedValue = validator.GetNullableTimeSpan(errorHandler, parseTimeSpan(postBackValue), allowEmpty); if (errorHandler.LastResult != ErrorCondition.NoError) { setup.ValidationErrorNotifier?.Invoke(); return; } validationMethod(validatedValue, validator); }); Labeler = textControl.Labeler; PageComponent = new CustomPhrasingComponent( new DisplayableElement( context => new DisplayableElementData( setup.DisplaySetup, () => new DisplayableElementLocalData( "span", focusDependentData: new DisplayableElementFocusDependentData( includeIdAttribute: true, jsInitStatements: "{0}.blur( function() {{ {1} }} ).keypress( function( e ) {{ {2} }} ).focus( function() {{ {3} }} ).mouseup( function( e ) {{ {4} }} );" .FormatWith( getTextControlExpression(context.Id), "ApplyTimeSpanFormat( this );", "if( !NumericalOnly( e, this ) ) e.preventDefault();", "this.value = this.value.replace( ':', '' ); this.select();", "e.preventDefault();"))), classes: elementClass.Add(setup.Classes ?? ElementClassSet.Empty), children: textControl.PageComponent.ToCollection())).ToCollection()); Validation = textControl.Validation; }
/// <summary> /// Creates a checkbox. /// </summary> /// <param name="value"></param> /// <param name="label">The checkbox label. Do not pass null. Pass an empty collection for no label.</param> /// <param name="setup">The setup object for the checkbox.</param> /// <param name="validationMethod">The validation method. Pass null if you’re only using this control for page modification.</param> public Checkbox( bool value, IReadOnlyCollection <PhrasingComponent> label, CheckboxSetup setup = null, Action <PostBackValue <bool>, Validator> validationMethod = null) { setup = setup ?? CheckboxSetup.Create(); var id = new ElementId(); var formValue = new FormValue <bool>( () => value, () => setup.IsReadOnly ? "" : id.Id, v => v.ToString(), rawValue => rawValue == null ? PostBackValueValidationResult <bool> .CreateValid(false) : rawValue == "on" ? PostBackValueValidationResult <bool> .CreateValid(true) : PostBackValueValidationResult <bool> .CreateInvalid()); PageComponent = getComponent( formValue, id, null, setup.DisplaySetup, setup.IsReadOnly, setup.Classes, setup.PageModificationValue, label, setup.Action, setup.ValueChangedAction, () => (setup.ValueChangedAction?.GetJsStatements() ?? "").ConcatenateWithSpace( setup.PageModificationValue.GetJsModificationStatements("this.checked"))); formValue.AddPageModificationValue(setup.PageModificationValue, v => v); if (validationMethod != null) { Validation = formValue.CreateValidation(validationMethod); } }
/// <summary> /// Creates a form item with these components. /// </summary> /// <param name="content">Do not pass null.</param> /// <param name="setup"></param> /// <param name="label">The form-item label.</param> /// <param name="validation"></param> public static FormItem ToFormItem( this IReadOnlyCollection <FlowComponent> content, FormItemSetup setup = null, IReadOnlyCollection <PhrasingComponent> label = null, EwfValidation validation = null) { label = label ?? Enumerable.Empty <PhrasingComponent>().Materialize(); return(new FormItem(setup, label, content, validation != null ? validation.ToCollection() : Enumerable.Empty <EwfValidation>().Materialize())); }
internal FormItem( FormItemSetup setup, IReadOnlyCollection <PhrasingComponent> label, IReadOnlyCollection <FlowComponent> content, EwfValidation validation) { Setup = setup ?? new FormItemSetup(); this.label = label; this.content = content; Validation = validation; ErrorSourceSet = validation != null ? new ErrorSourceSet(validations: validation.ToCollection()) : null; }
/// <summary> /// Creates a file-upload control. /// </summary> /// <param name="displaySetup"></param> /// <param name="validationPredicate"></param> /// <param name="validationErrorNotifier"></param> /// <param name="validationMethod">The validation method. Pass null if you’re only using this control for page modification.</param> public FileUpload( DisplaySetup displaySetup = null, Func <bool, bool> validationPredicate = null, Action validationErrorNotifier = null, Action <RsFile, Validator> validationMethod = null) { Labeler = new FormControlLabeler(); var id = new ElementId(); var formValue = new FormValue <HttpPostedFile>( () => null, () => id.Id, v => "", rawValue => rawValue == null ? PostBackValueValidationResult <HttpPostedFile> .CreateInvalid() : PostBackValueValidationResult <HttpPostedFile> .CreateValid(rawValue.ContentLength > 0 ? rawValue : null)); PageComponent = new CustomPhrasingComponent( new DisplayableElement( context => { id.AddId(context.Id); Labeler.AddControlId(context.Id); EwfPage.Instance.Form.Enctype = "multipart/form-data"; return(new DisplayableElementData( displaySetup, () => { var attributes = new List <Tuple <string, string> >(); attributes.Add(Tuple.Create("type", "file")); attributes.Add(Tuple.Create("name", context.Id)); return new DisplayableElementLocalData( "input", new FocusabilityCondition(true), isFocused => { if (isFocused) { attributes.Add(Tuple.Create("autofocus", "autofocus")); } return new DisplayableElementFocusDependentData(attributes: attributes); }); })); }, formValue: formValue).ToCollection()); if (validationMethod != null) { Validation = formValue.CreateValidation( (postBackValue, validator) => { if (validationPredicate != null && !validationPredicate(postBackValue.ChangedOnPostBack)) { return; } validationMethod(getRsFile(postBackValue.Value), validator); }); } }
/// <summary> /// Creates a radio button. /// </summary> internal FlowCheckbox(FlowRadioButtonSetup setup, Checkbox checkbox) { PageComponent = getComponent( setup.DisplaySetup, setup.Classes, setup.RadioButtonSetup.PageModificationValue, checkbox, setup.HighlightedWhenSelected, setup.NestedContentGetter, setup.NestedContentAlwaysDisplayed); Validation = checkbox.Validation; }
/// <summary> /// Creates a form item. /// </summary> protected FormItem(FormItemLabel label, Control control, int?cellSpan, TextAlignment textAlignment, EwfValidation validation) { if (label == null) { throw new ApplicationException("The label cannot be a null FormItemLabel reference."); } this.label = label; this.control = control; this.cellSpan = cellSpan; this.textAlignment = textAlignment; this.validation = validation; }
/// <summary> /// Creates a check box. /// </summary> /// <param name="isChecked"></param> /// <param name="validationMethod">The validation method. Do not pass null.</param> /// <param name="label">Do not pass null.</param> /// <param name="setup">The setup object for the check box.</param> public BlockCheckBox(bool isChecked, Action <PostBackValue <bool>, Validator> validationMethod, string label = "", BlockCheckBoxSetup setup = null) { this.setup = setup ?? new BlockCheckBoxSetup(); checkBoxFormValue = EwfCheckBox.GetFormValue(isChecked, this); this.label = label; action = this.setup.Action ?? FormState.Current.DefaultAction; validation = checkBoxFormValue.CreateValidation(validationMethod); nestedControls = this.setup.NestedControlListGetter != null?this.setup.NestedControlListGetter().ToImmutableArray() : ImmutableArray <Control> .Empty; }
/// <summary> /// Creates a radio button. /// </summary> internal BlockCheckBox( FormValue <CommonCheckBox> formValue, string label, BlockCheckBoxSetup setup, Func <IEnumerable <string> > jsClickHandlerStatementListGetter, EwfValidation validation, string listItemId = null) { radioButtonFormValue = formValue; radioButtonListItemId = listItemId; this.label = label; this.setup = setup; action = setup.Action ?? FormState.Current.DefaultAction; jsClickHandlerStatementLists.Add(jsClickHandlerStatementListGetter); this.validation = validation; nestedControls = setup.NestedControlListGetter != null?setup.NestedControlListGetter().ToImmutableArray() : ImmutableArray <Control> .Empty; }
/// <summary> /// Creates a hidden field. /// </summary> /// <param name="value">Do not pass null.</param> /// <param name="id"></param> /// <param name="pageModificationValue"></param> /// <param name="validationMethod">The validation method. Pass null if you’re only using this control for page modification.</param> /// <param name="jsInitStatementGetter">A function that takes the field’s ID and returns the JavaScript statements that should be executed when the DOM is /// loaded. Do not return null.</param> public EwfHiddenField( string value, HiddenFieldId id = null, PageModificationValue <string> pageModificationValue = null, Action <PostBackValue <string>, Validator> validationMethod = null, Func <string, string> jsInitStatementGetter = null) { pageModificationValue = pageModificationValue ?? new PageModificationValue <string>(); var elementId = new ElementId(); var formValue = new FormValue <string>( () => value, () => elementId.Id, v => v, rawValue => rawValue != null ? PostBackValueValidationResult <string> .CreateValid(rawValue) : PostBackValueValidationResult <string> .CreateInvalid()); component = new ElementComponent( context => { elementId.AddId(context.Id); id?.AddId(context.Id); return(new ElementData( () => { var attributes = new List <Tuple <string, string> >(); attributes.Add(Tuple.Create("type", "hidden")); attributes.Add(Tuple.Create("name", context.Id)); attributes.Add(Tuple.Create("value", pageModificationValue.Value)); return new ElementLocalData( "input", focusDependentData: new ElementFocusDependentData( attributes: attributes, includeIdAttribute: id != null || pageModificationValue != null || jsInitStatementGetter != null, jsInitStatements: StringTools.ConcatenateWithDelimiter( " ", pageModificationValue != null ? "$( '#{0}' ).change( function() {{ {1} }} );".FormatWith( context.Id, pageModificationValue.GetJsModificationStatements("$( this ).val()")) : "", jsInitStatementGetter?.Invoke(context.Id) ?? ""))); })); }, formValue: formValue); formValue.AddPageModificationValue(pageModificationValue, v => v); if (validationMethod != null) { validation = formValue.CreateValidation(validationMethod); } }
/// <summary> /// Creates a checkbox. /// </summary> /// <param name="value"></param> /// <param name="label">The checkbox label. Do not pass null. Pass an empty collection for no label.</param> /// <param name="setup">The setup object for the flow checkbox.</param> /// <param name="validationMethod">The validation method. Pass null if you’re only using the checkbox for page modification.</param> public FlowCheckbox( bool value, IReadOnlyCollection <PhrasingComponent> label, FlowCheckboxSetup setup = null, Action <PostBackValue <bool>, Validator> validationMethod = null) { setup = setup ?? FlowCheckboxSetup.Create(); var checkbox = new Checkbox(value, label, setup: setup.CheckboxSetup, validationMethod: validationMethod); PageComponent = getComponent( setup.DisplaySetup, setup.Classes, setup.CheckboxSetup.PageModificationValue, checkbox, setup.HighlightedWhenChecked, setup.NestedContentGetter, setup.NestedContentAlwaysDisplayed); Validation = checkbox.Validation; }
/// <summary> /// Creates a radio button. /// </summary> internal Checkbox( FormValue <ElementId> formValue, ElementId id, RadioButtonSetup setup, IReadOnlyCollection <PhrasingComponent> label, FormAction selectionChangedAction, Func <string> jsClickStatementGetter, EwfValidation validation, string listItemId = null) { PageComponent = getComponent( formValue, id, listItemId, setup.DisplaySetup, setup.IsReadOnly, setup.Classes, setup.PageModificationValue, label, setup.Action, selectionChangedAction, () => setup.IsReadOnly ? "" : (setup.PageModificationValue.Value ? "" : selectionChangedAction?.GetJsStatements() ?? "") .ConcatenateWithSpace(jsClickStatementGetter())); Validation = validation; }
/// <summary> /// Creates a form item with this component. /// </summary> /// <param name="content">Do not pass null.</param> /// <param name="setup"></param> /// <param name="label">The form-item label.</param> /// <param name="validation"></param> public static FormItem ToFormItem( this FlowComponent content, FormItemSetup setup = null, IReadOnlyCollection <PhrasingComponent> label = null, EwfValidation validation = null) => content.ToCollection().ToFormItem(setup: setup, label: label, validation: validation);
/// <summary> /// Adds an extraneous validation to this form item. Useful when you have validation logic that needs to execute in a different set of data modifications /// than the form item’s built-in validation. For example, you may have a form item that modifies a piece of component state during an intermediate /// post-back. If you later need to update the state item’s durable value during a full post-back, and this involves additional validation, you can create a /// separate <see cref="EwfValidation"/> and use this method to keep the errors within the form item. /// </summary> public FormItem AddExtraneousValidation(EwfValidation validation) { return(new FormItem(Setup, label, content, validations.Append(validation).Materialize())); }
/// <summary> /// Creates a modification error placeholder for the specified validation, or for the top modification errors if no validation is passed. /// </summary> public ModificationErrorPlaceholder(EwfValidation validation, ErrorDisplayStyle displayStyle) { this.validation = validation; this.displayStyle = displayStyle; }
void ValidationListInternal.AddValidation(EwfValidation validation) { ((ValidationListInternal)dataModification).AddValidation(validation); }
/// <summary> /// Creates a simple HTML editor. /// </summary> /// <param name="value">Do not pass null.</param> /// <param name="allowEmpty"></param> /// <param name="validationMethod">The validation method. Do not pass null.</param> /// <param name="setup">The setup object for the HTML editor.</param> /// <param name="maxLength"></param> public WysiwygHtmlEditor( string value, bool allowEmpty, Action <string, Validator> validationMethod, WysiwygHtmlEditorSetup setup = null, int?maxLength = null) { setup = setup ?? new WysiwygHtmlEditorSetup(); var id = new ElementId(); FormValue <string> formValue = null; formValue = new FormValue <string>( () => value, () => setup.IsReadOnly ? "" : id.Id, v => v, rawValue => { if (rawValue == null) { return(PostBackValueValidationResult <string> .CreateInvalid()); } // This hack prevents the NewLine that CKEditor seems to always add to the end of the textarea from causing // ValueChangedOnPostBack to always return true. if (rawValue.EndsWith(Environment.NewLine) && rawValue.Remove(rawValue.Length - Environment.NewLine.Length) == formValue.GetDurableValue()) { rawValue = formValue.GetDurableValue(); } return(PostBackValueValidationResult <string> .CreateValid(rawValue)); }); var modificationValue = new PageModificationValue <string>(); component = new ElementComponent( context => { id.AddId(context.Id); var displaySetup = setup.DisplaySetup ?? new DisplaySetup(true); var jsShowStatements = getJsShowStatements(context.Id, setup.CkEditorConfiguration); displaySetup.AddJsShowStatements(jsShowStatements); displaySetup.AddJsHideStatements("CKEDITOR.instances.{0}.destroy(); $( '#{0}' ).css( 'display', 'none' );".FormatWith(context.Id)); return(new ElementData( () => { var attributes = new List <Tuple <string, string> >(); if (setup.IsReadOnly) { attributes.Add(Tuple.Create("disabled", "disabled")); } else { attributes.Add(Tuple.Create("name", context.Id)); } if (!displaySetup.ComponentsDisplayed) { attributes.Add(Tuple.Create("style", "display: none")); } return new ElementLocalData( "textarea", attributes: attributes, includeIdAttribute: true, jsInitStatements: displaySetup.ComponentsDisplayed ? jsShowStatements : ""); }, children: new TextNode(() => EwfTextBox.GetTextareaValue(modificationValue.Value)).ToCollection())); }, formValue: formValue); validation = formValue.CreateValidation( (postBackValue, validator) => { if (setup.ValidationPredicate != null && !setup.ValidationPredicate(postBackValue.ChangedOnPostBack)) { return; } var errorHandler = new ValidationErrorHandler("HTML"); var validatedValue = maxLength.HasValue ? validator.GetString(errorHandler, postBackValue.Value, allowEmpty, maxLength.Value) : validator.GetString(errorHandler, postBackValue.Value, allowEmpty); if (errorHandler.LastResult != ErrorCondition.NoError) { setup.ValidationErrorNotifier(); return; } validationMethod(validatedValue, validator); }); formValue.AddPageModificationValue(modificationValue, v => v); }
/// <summary> /// Returns the errors from the specified validation. /// </summary> public IReadOnlyCollection <string> GetErrors(EwfValidation validation) { return(dictionary[validation]); }
void ValidationList.AddValidation(EwfValidation validation) { validations.Add(validation); }
/// <summary> /// Creates a date-and-time control. /// </summary> /// <param name="value"></param> /// <param name="allowEmpty"></param> /// <param name="setup">The setup object for the date-and-time control.</param> /// <param name="minValue">The earliest acceptable date.</param> /// <param name="maxValue">The latest acceptable date.</param> /// <param name="validationMethod">The validation method. Pass null if you’re only using this control for page modification.</param> public DateAndTimeControl( LocalDateTime?value, bool allowEmpty, DateAndTimeControlSetup setup = null, LocalDate?minValue = null, LocalDate?maxValue = null, Action <LocalDateTime?, Validator> validationMethod = null) { setup = setup ?? DateAndTimeControlSetup.Create(); var textControl = new TextControl( value.HasValue ? value.Value.ToDateTimeUnspecified().ToMonthDayYearString() + " " + value.Value.ToDateTimeUnspecified().ToHourAndMinuteString() : "", allowEmpty, setup: setup.IsReadOnly ? TextControlSetup.CreateReadOnly(validationPredicate: setup.ValidationPredicate, validationErrorNotifier: setup.ValidationErrorNotifier) : TextControlSetup.Create( autoFillTokens: setup.AutoFillTokens, action: new SpecifiedValue <FormAction>(setup.Action), valueChangedAction: setup.ValueChangedAction, pageModificationValue: setup.PageModificationValue, validationPredicate: setup.ValidationPredicate, validationErrorNotifier: setup.ValidationErrorNotifier), validationMethod: validationMethod == null ? (Action <string, Validator>)null : (postBackValue, validator) => { var errorHandler = new ValidationErrorHandler("date and time"); var validatedValue = validator.GetNullableDateTime( errorHandler, postBackValue.ToUpper(), TewlContrib.DateTimeTools.MonthDayYearFormats.Select(i => i + " " + TewlContrib.DateTimeTools.HourAndMinuteFormat).ToArray(), allowEmpty, minValue?.ToDateTimeUnspecified() ?? DateTime.MinValue, maxValue?.PlusDays(1).ToDateTimeUnspecified() ?? DateTime.MaxValue); if (errorHandler.LastResult != ErrorCondition.NoError) { setup.ValidationErrorNotifier?.Invoke(); return; } validationMethod( validatedValue.HasValue ? (LocalDateTime?)LocalDateTime.FromDateTime(validatedValue.Value) : null, validator); }); Labeler = textControl.Labeler; PageComponent = new CustomPhrasingComponent( new DisplayableElement( context => new DisplayableElementData( setup.DisplaySetup, () => new DisplayableElementLocalData( "span", focusDependentData: new DisplayableElementFocusDependentData( includeIdAttribute: true, jsInitStatements: "{0}.datetimepicker( {{ {1} }} );".FormatWith( getTextControlExpression(context.Id), StringTools.ConcatenateWithDelimiter( ", ", minValue.HasValue ? "minDate: {0}".FormatWith("new Date( {0}, {1} - 1, {2} )".FormatWith(minValue.Value.Year, minValue.Value.Month, minValue.Value.Day)) : "", maxValue.HasValue ? "maxDate: {0}".FormatWith("new Date( {0}, {1} - 1, {2} )".FormatWith(maxValue.Value.Year, maxValue.Value.Month, maxValue.Value.Day)) : "", "timeFormat: 'h:mmt'", "stepMinute: {0}".FormatWith(setup.MinuteInterval.Value))))), classes: elementClass.Add(setup.Classes ?? ElementClassSet.Empty), children: textControl.PageComponent.ToCollection() .Concat( setup.IsReadOnly ? Enumerable.Empty <PhrasingComponent>() : new EwfButton( new CustomButtonStyle( children: new GenericPhrasingContainer( new FontAwesomeIcon("fa-calendar-o", "fa-stack-2x").ToCollection() .Append(new FontAwesomeIcon("fa-clock-o", "fa-stack-1x")) .Materialize(), classes: new ElementClass("fa-stack")).ToCollection()), behavior: new CustomButtonBehavior(() => "{0}.datetimepicker( 'show' );".FormatWith(getTextControlExpression(context.Id))), classes: new ElementClass("icon")).ToCollection()) .Materialize())).ToCollection()); Validation = textControl.Validation; }
/// <summary> /// Creates a modification error placeholder for the specified validation, or for the top modification errors if no validation is passed. /// </summary> public ModificationErrorPlaceholder( EwfValidation validation, ErrorDisplayStyle displayStyle ) { this.validation = validation; this.displayStyle = displayStyle; }
void ValidationListInternal.AddValidation( EwfValidation validation ) { validations.Add( validation ); }
/// <summary> /// Creates a checkbox list. /// </summary> /// <param name="setup">The setup object for the checkbox list. Do not pass null.</param> /// <param name="value">The selected-item IDs.</param> /// <param name="validationMethod">The validation method. Pass null if you’re only using this control for page modification.</param> public CheckboxList( CheckboxListSetup <ItemIdType> setup, IEnumerable <ItemIdType> value, Action <IReadOnlyCollection <ItemIdType>, Validator> validationMethod = null) { var valueSet = value.ToImmutableHashSet(); var selectedItemIdsInPostBack = new List <ItemIdType>(); var selectionChangedOnPostBack = false; var checkboxes = setup.Items.Select( i => new FlowCheckbox( valueSet.Contains(i.Id), i.Label.ToComponents(), setup: FlowCheckboxSetup.Create( highlightedWhenChecked: true, action: new SpecifiedValue <FormAction>(setup.Action), valueChangedAction: setup.SelectionChangedAction), validationMethod: (postBackValue, validator) => { if (postBackValue.Value) { selectedItemIdsInPostBack.Add(i.Id); } selectionChangedOnPostBack = selectionChangedOnPostBack || postBackValue.ChangedOnPostBack; })) .Materialize(); var contentContainerId = new ElementId(); PageComponent = new GenericFlowContainer( (setup.IncludeSelectAndDeselectAllButtons ? new GenericFlowContainer( new InlineList( new EwfButton( new StandardButtonStyle( "Select All", buttonSize: ButtonSize.ShrinkWrap, icon: new ActionComponentIcon(new FontAwesomeIcon("fa-check-square-o"))), behavior: new CustomButtonBehavior( () => "$( '#{0}' ).find( 'input[type=checkbox]:not(:checked)' ).click();".FormatWith(contentContainerId.Id))).ToCollection() .ToComponentListItem() .ToCollection() .Append( new EwfButton( new StandardButtonStyle( "Deselect All", buttonSize: ButtonSize.ShrinkWrap, icon: new ActionComponentIcon(new FontAwesomeIcon("fa-square-o"))), behavior: new CustomButtonBehavior( () => "$( '#{0}' ).find( 'input[type=checkbox]:checked' ).click();".FormatWith(contentContainerId.Id))).ToCollection() .ToComponentListItem())).ToCollection(), classes: CheckboxListCssElementCreator.ActionContainerClass).ToCollection() : Enumerable.Empty <FlowComponent>()).Append( new DisplayableElement( context => { contentContainerId.AddId(context.Id); return(new DisplayableElementData( null, () => new DisplayableElementLocalData( "div", focusDependentData: new DisplayableElementFocusDependentData( attributes: setup.MinColumnWidth != null ? Tuple.Create("style", "column-width: {0}".FormatWith(((CssLength)setup.MinColumnWidth).Value)).ToCollection() : null, includeIdAttribute: true)), classes: CheckboxListCssElementCreator.ContentContainerClass, children: new RawList(from i in checkboxes select i.PageComponent.ToCollection().ToComponentListItem()).ToCollection())); })) .Materialize(), displaySetup: setup.DisplaySetup, classes: CheckboxListCssElementCreator.ListClass); if (validationMethod != null) { Validation = new EwfValidation( validator => { if (setup.ValidationPredicate != null && !setup.ValidationPredicate(selectionChangedOnPostBack)) { return; } validationMethod(selectedItemIdsInPostBack, validator); }); } }
private void handleValidationErrors( EwfValidation validation, IEnumerable<string> errorMessages ) { if( !modErrorDisplaysByValidation.ContainsKey( validation ) || !errorMessages.Any() ) return; foreach( var displayKey in modErrorDisplaysByValidation[ validation ] ) { var errorsByDisplay = AppRequestState.Instance.EwfPageRequestState.InLineModificationErrorsByDisplay; errorsByDisplay[ displayKey ] = errorsByDisplay.ContainsKey( displayKey ) ? errorsByDisplay[ displayKey ].Concat( errorMessages ) : errorMessages; } }
/// <summary> /// Creates a time control. /// </summary> /// <param name="value"></param> /// <param name="allowEmpty"></param> /// <param name="setup">The setup object for the time control.</param> /// <param name="minValue">The earliest allowed time.</param> /// <param name="maxValue">The latest allowed time. This can be earlier than <paramref name="minValue"/> to create a range spanning midnight.</param> /// <param name="minuteInterval">Allows the user to select values only in the given increments. Be aware that other values can still be sent from the /// browser via a crafted request.</param> /// <param name="validationMethod">The validation method. Pass null if you’re only using this control for page modification.</param> public TimeControl( LocalTime?value, bool allowEmpty, TimeControlSetup setup = null, LocalTime?minValue = null, LocalTime?maxValue = null, int minuteInterval = 15, Action <LocalTime?, Validator> validationMethod = null) { setup = setup ?? TimeControlSetup.Create(); minValue = minValue ?? LocalTime.Midnight; if (minuteInterval < 30) { var textControl = new TextControl( value.HasValue ? new TimeSpan(value.Value.TickOfDay).ToTimeOfDayHourAndMinuteString() : "", allowEmpty, setup: setup.IsReadOnly ? TextControlSetup.CreateReadOnly(validationPredicate: setup.ValidationPredicate, validationErrorNotifier: setup.ValidationErrorNotifier) : TextControlSetup.Create( autoFillTokens: setup.AutoFillTokens, action: new SpecifiedValue <FormAction>(setup.Action), valueChangedAction: setup.ValueChangedAction, pageModificationValue: setup.PageModificationValue, validationPredicate: setup.ValidationPredicate, validationErrorNotifier: setup.ValidationErrorNotifier), validationMethod: validationMethod == null ? (Action <string, Validator>)null : (postBackValue, validator) => { var errorHandler = new ValidationErrorHandler("time"); var validatedValue = validator.GetNullableTimeOfDayTimeSpan( errorHandler, postBackValue.ToUpper(), TewlContrib.DateTimeTools.HourAndMinuteFormat.ToCollection().ToArray(), allowEmpty) .ToNewUnderlyingValue(v => LocalTime.FromTicksSinceMidnight(v.Ticks)); if (errorHandler.LastResult != ErrorCondition.NoError) { setup.ValidationErrorNotifier?.Invoke(); return; } var wrap = maxValue < minValue.Value; if (!wrap ? validatedValue < minValue.Value || validatedValue > maxValue : validatedValue < minValue.Value && validatedValue > maxValue) { validator.NoteErrorAndAddMessage("The time is too early or too late."); setup.ValidationErrorNotifier?.Invoke(); return; } validationMethod(validatedValue, validator); }); Labeler = textControl.Labeler; PageComponent = new DisplayableElement( context => new DisplayableElementData( setup.DisplaySetup, () => new DisplayableElementLocalData( "div", focusDependentData: new DisplayableElementFocusDependentData( includeIdAttribute: true, jsInitStatements: "{0}.timepicker( {{ {1} }} );".FormatWith( getTextControlExpression(context.Id), StringTools.ConcatenateWithDelimiter( ", ", "timeFormat: 'h:mmt'", "stepMinute: {0}".FormatWith(minuteInterval), "showButtonPanel: false")))), classes: elementClass.Add(setup.Classes ?? ElementClassSet.Empty), children: textControl.PageComponent.ToCollection() .Concat( setup.IsReadOnly ? Enumerable.Empty <PhrasingComponent>() : new EwfButton( new CustomButtonStyle(children: new FontAwesomeIcon("fa-clock-o").ToCollection()), behavior: new CustomButtonBehavior(() => "{0}.timepicker( 'show' );".FormatWith(getTextControlExpression(context.Id))), classes: new ElementClass("icon")).ToCollection()) .Materialize())); Validation = textControl.Validation; } else { var items = from time in getTimes(minValue.Value, maxValue, minuteInterval) let timeSpan = new TimeSpan(time.TickOfDay) select SelectListItem.Create <LocalTime?>(time, timeSpan.ToTimeOfDayHourAndMinuteString()); var selectList = SelectList.CreateDropDown( setup.IsReadOnly ? DropDownSetup.CreateReadOnly( items, placeholderText: "", validationPredicate: setup.ValidationPredicate, validationErrorNotifier: setup.ValidationErrorNotifier) : DropDownSetup.Create( items, placeholderText: "", autoFillTokens: setup.AutoFillTokens, action: new SpecifiedValue <FormAction>(setup.Action), selectionChangedAction: setup.ValueChangedAction, validationPredicate: setup.ValidationPredicate, validationErrorNotifier: setup.ValidationErrorNotifier), value, placeholderIsValid: allowEmpty, validationMethod: validationMethod); Labeler = selectList.Labeler; PageComponent = new GenericFlowContainer( selectList.PageComponent.ToCollection(), displaySetup: setup.DisplaySetup, classes: elementClass.Add(setup.Classes ?? ElementClassSet.Empty)); Validation = selectList.Validation; } }
/// <summary> /// Returns the errors from the specified validation. /// </summary> public IReadOnlyCollection <string> GetValidationErrors(EwfValidation validation) => errorsByValidation[validation];
void ValidationListInternal.AddValidation( EwfValidation validation ) { ( (ValidationListInternal)dataModification ).AddValidation( validation ); }
public void AddTopValidationMethod( Action<PostBackValueDictionary, Validator> validationMethod ) { var validation = new EwfValidation( validationMethod, this ); topValidations.Add( validation ); }
void ValidationListInternal.AddValidation(EwfValidation validation) { validations.Add(validation); }
/// <summary> /// If you are using the results of this method to create controls, put them in a naming container so that when the controls differ before and after a /// transfer, other parts of the page such as form control IDs do not get affected. /// </summary> internal IEnumerable<string> AddModificationErrorDisplayAndGetErrors( Control control, string keySuffix, EwfValidation validation ) { var key = control.UniqueID + keySuffix; if( modErrorDisplaysByValidation.ContainsKey( validation ) ) modErrorDisplaysByValidation[ validation ].Add( key ); else modErrorDisplaysByValidation.Add( validation, key.ToSingleElementArray().ToList() ); // We want to ignore all of the problems that could happen, such as the key not existing in the dictionary. This problem will be shown in a more helpful // way when we compare form control hashes after a transfer. // // Avoid using exceptions here if possible. This method is sometimes called many times during a request, and we've seen exceptions take as long as 50 ms // each when debugging. IEnumerable<string> value; return AppRequestState.Instance.EwfPageRequestState.InLineModificationErrorsByDisplay.TryGetValue( key, out value ) ? value : new string[ 0 ]; }
void ValidationList.AddValidation(EwfValidation validation) { ((ValidationList)dataModification).AddValidation(validation); }
public void AddTopValidationMethod(Action <PostBackValueDictionary, Validator> validationMethod) { var validation = new EwfValidation(validationMethod, this); topValidations.Add(validation); }