private NavFormControl(
     NavFormControlSetup setup, Func <Action <NavFormControlValidationResult, Validator>, FormControl <PhrasingComponent> > formControlGetter)
 {
     formItemGetter = postBackId => {
         var destination = new DataValue <ResourceInfo>();
         var postBack    = PostBack.CreateFull(id: postBackId, actionGetter: () => new PostBackAction(destination.Value));
         return(FormState.ExecuteWithDataModificationsAndDefaultAction(
                    postBack.ToCollection(),
                    () => {
             var formControl = formControlGetter(
                 (result, validator) => {
                 if (result.Destination != null)
                 {
                     destination.Value = result.Destination;
                 }
                 else
                 {
                     validator.NoteErrorAndAddMessage(result.ErrorMessage);
                 }
             });
             return new DisplayableElement(
                 context => new DisplayableElementData(
                     null,
                     () => new DisplayableElementLocalData(
                         "span",
                         focusDependentData: new DisplayableElementFocusDependentData(
                             attributes: new ElementAttribute(
                                 "style",
                                 "display: inline-block; width: {0}".FormatWith(((CssLength)setup.Width).Value)).ToCollection())),
                     children: formControl.PageComponent.ToCollection())).ToFormItem(validation: formControl.Validation);
         }));
     };
 }
        protected override PageContent getContent()
        {
            if (Password.Any())
            {
                return(new UiPageContent(
                           pageLoadPostBack: PostBack.CreateFull(
                               modificationMethod: () => logIn(HideWarnings),
                               actionGetter: () => new PostBackAction(new ExternalResource(ReturnUrl)))).Add(new Paragraph("Please wait.".ToComponents())));
            }

            return(FormState.ExecuteWithDataModificationsAndDefaultAction(
                       PostBack.CreateFull(modificationMethod: () => logIn(false), actionGetter: () => new PostBackAction(new ExternalResource(ReturnUrl)))
                       .ToCollection(),
                       () => new UiPageContent(contentFootActions: new ButtonSetup("Log In").ToCollection()).Add(
                           FormItemList.CreateStack(
                               items: new TextControl(
                                   "",
                                   true,
                                   setup: TextControlSetup.CreateObscured(),
                                   validationMethod: (postBackValue, validator) => {
                // NOTE: Using a single password here is a hack. The real solution is being able to use System Manager credentials, which is a goal.
                var passwordMatch = postBackValue == ConfigurationStatics.SystemGeneralProvider.IntermediateLogInPassword;
                if (!passwordMatch)
                {
                    validator.NoteErrorAndAddMessage("Incorrect password.");
                }
            }).ToFormItem(label: "Enter your password for this non-live installation".ToComponents())
                               .ToCollection()))));
        }
        private IReadOnlyCollection <FlowComponent> getUploadComponents(
            int fileCollectionId, IReadOnlyCollection <BlobFile> files, DisplaySetup displaySetup, string postBackIdBase,
            Action <RsFile, Validator> uploadValidationMethod, NewFileNotificationMethod fileCreatedOrReplacedNotifier)
        {
            RsFile file = null;
            var    dm   = PostBack.CreateFull(
                id: PostBack.GetCompositeId(postBackIdBase, "add"),
                firstModificationMethod: () => {
                if (file == null)
                {
                    return;
                }

                var existingFile = files.SingleOrDefault(i => i.FileName == file.FileName);
                int newFileId;
                if (existingFile != null)
                {
                    BlobStorageStatics.SystemProvider.UpdateFile(
                        existingFile.FileId,
                        file.FileName,
                        file.Contents,
                        BlobStorageStatics.GetContentTypeForPostedFile(file));
                    newFileId = existingFile.FileId;
                }
                else
                {
                    newFileId = BlobStorageStatics.SystemProvider.InsertFile(
                        fileCollectionId,
                        file.FileName,
                        file.Contents,
                        BlobStorageStatics.GetContentTypeForPostedFile(file));
                }

                fileCreatedOrReplacedNotifier?.Invoke(newFileId);
                EwfPage.AddStatusMessage(StatusMessageType.Info, "File uploaded successfully.");
            });

            return(FormState.ExecuteWithDataModificationsAndDefaultAction(
                       dm.ToCollection(),
                       () => new StackList(
                           new FileUpload(
                               validationMethod: (postBackValue, validator) => {
                file = postBackValue;
                uploadValidationMethod?.Invoke(postBackValue, validator);
            }).ToFormItem()
                           .ToListItem()
                           .Append(new EwfButton(new StandardButtonStyle("Upload new file")).ToCollection().ToComponentListItem())).ToFormItem(
                           setup: new FormItemSetup(displaySetup: displaySetup),
                           label: "Select and upload a new file:".ToComponents())
                       .ToComponentCollection()));
        }
        void ControlTreeDataLoader.LoadData()
        {
            FormState.ExecuteWithDataModificationsAndDefaultAction(
                dataModifications,
                () => {
                if (hideIfEmpty && !formItems.Any())
                {
                    Visible = false;
                    return;
                }

                CssClass = CssClass.ConcatenateWithSpace(CssElementCreator.CssClass);
                if (IncludeButtonWithThisText != null)
                {
                    // We need to do logic to get the button to be on the right of the row.
                    if (useFormItemListMode && numberOfColumns.HasValue)
                    {
                        var widthOfLastRowWithButton     = getFormItemRows(formItems, numberOfColumns.Value).Last().Sum(getCellSpan) + defaultFormItemCellSpan;
                        var numberOfPlaceholdersRequired = 0;
                        if (widthOfLastRowWithButton < numberOfColumns.Value)
                        {
                            numberOfPlaceholdersRequired = numberOfColumns.Value - widthOfLastRowWithButton;
                        }
                        if (widthOfLastRowWithButton > numberOfColumns.Value)
                        {
                            numberOfPlaceholdersRequired = numberOfColumns.Value - ((widthOfLastRowWithButton - numberOfColumns.Value) % numberOfColumns.Value);
                        }

                        numberOfPlaceholdersRequired.Times(() => formItems.Add(getPlaceholderFormItem()));
                    }
                    formItems.Add(
                        FormItem.Create(
                            "",
                            new PostBackButton(new ButtonActionControlStyle(IncludeButtonWithThisText), postBack: EwfPage.Instance.DataUpdatePostBack)
                    {
                        Width = Unit.Percentage(50)
                    },
                            textAlignment: TextAlignment.Right,
                            cellSpan: defaultFormItemCellSpan));
                }
                Controls.Add(useFormItemListMode ? getTableForFormItemList() : getTableForFormItemTable());
            });
        }
        protected override PageContent getContent()
        {
            var body = new DataValue <string>();

            return(FormState.ExecuteWithDataModificationsAndDefaultAction(
                       PostBack.CreateFull(
                           modificationMethod: () => {
                var message = new EmailMessage
                {
                    Subject = "Support request from {0} in {1}".FormatWith(
                        AppTools.User.FriendlyName.Any() ? AppTools.User.FriendlyName : AppTools.User.Email,
                        ConfigurationStatics.SystemDisplayName),
                    BodyHtml = body.Value.GetTextAsEncodedHtml()
                };
                message.ReplyToAddresses.Add(new EmailAddress(AppTools.User.Email, AppTools.User.FriendlyName));
                message.ToAddresses.AddRange(EmailStatics.GetAdministratorEmailAddresses());
                EmailStatics.SendEmailWithDefaultFromAddress(message);
                AddStatusMessage(StatusMessageType.Info, "Your message has been sent.");
            },
                           actionGetter: () => new PostBackAction(new ExternalResource(ReturnUrl)))
                       .ToCollection(),
                       () => new UiPageContent(contentFootActions: new ButtonSetup("Send Message").ToCollection())
                       .Add(new Paragraph("You may report any problems, make suggestions, or ask for help here.".ToComponents()))
                       .Add(
                           FormItemList.CreateStack(
                               items: new EmailAddress(AppTools.User.Email, AppTools.User.FriendlyName).ToMailAddress()
                               .ToString()
                               .ToComponents()
                               .ToFormItem(label: "From".ToComponents())
                               .Append(
                                   "{0} ({1} for this system)".FormatWith(
                                       StringTools.GetEnglishListPhrase(EmailStatics.GetAdministratorEmailAddresses().Select(i => i.DisplayName), true),
                                       "support contacts".ToQuantity(EmailStatics.GetAdministratorEmailAddresses().Count(), showQuantityAs: ShowQuantityAs.None))
                                   .ToComponents()
                                   .ToFormItem(label: "To".ToComponents()))
                               .Append(
                                   body.ToTextControl(false, setup: TextControlSetup.Create(numberOfRows: 10), value: "").ToFormItem(label: "Message".ToComponents()))
                               .Materialize()))));
        }
        /// <summary>
        /// Creates a modal credit-card collector that is implemented with Stripe Checkout. When the window’s submit button is clicked, the credit card is charged
        /// or otherwise used.
        /// </summary>
        /// <param name="jsOpenStatements">The JavaScript statement list that will open this credit-card collector.</param>
        /// <param name="testPublishableKey">Your test publishable API key. Will be used in non-live installations. Do not pass null.</param>
        /// <param name="livePublishableKey">Your live publishable API key. Will be used in live installations. Do not pass null.</param>
        /// <param name="name">See https://stripe.com/docs/legacy-checkout. Do not pass null.</param>
        /// <param name="description">See https://stripe.com/docs/legacy-checkout. Do not pass null.</param>
        /// <param name="amountInDollars">See https://stripe.com/docs/legacy-checkout, but note that this parameter is in dollars, not cents</param>
        /// <param name="testSecretKey">Your test secret API key. Will be used in non-live installations. Do not pass null.</param>
        /// <param name="liveSecretKey">Your live secret API key. Will be used in live installations. Do not pass null.</param>
        /// <param name="successHandler">A method that executes if the credit-card submission is successful. The first parameter is the charge ID and the second
        /// parameter is the amount of the charge, in dollars.</param>
        /// <param name="prefilledEmailAddressOverride">By default, the email will be prefilled with AppTools.User.Email if AppTools.User is not null. You can
        /// override this with either a specified email address (if user is paying on behalf of someone else) or the empty string (to force the user to type in the
        /// email address).</param>
        public CreditCardCollector(
            JsStatementList jsOpenStatements, string testPublishableKey, string livePublishableKey, string name, string description, decimal?amountInDollars,
            string testSecretKey, string liveSecretKey, Func <string, decimal, StatusMessageAndDestination> successHandler,
            string prefilledEmailAddressOverride = null)
        {
            if (!EwfApp.Instance.RequestIsSecure(HttpContext.Current.Request))
            {
                throw new ApplicationException("Credit-card collection can only be done from secure pages.");
            }

            if (amountInDollars.HasValue && amountInDollars.Value.DollarValueHasFractionalCents())
            {
                throw new ApplicationException("Amount must not include fractional cents.");
            }

            var          token = new DataValue <string>();
            ResourceInfo successDestination = null;
            var          postBack           = PostBack.CreateFull(
                id: PostBack.GetCompositeId("ewfCreditCardCollection", description),
                modificationMethod: () => {
                // We can add support later for customer creation, subscriptions, etc. as needs arise.
                if (!amountInDollars.HasValue)
                {
                    throw new ApplicationException("Only simple charges are supported at this time.");
                }

                StripeCharge response;
                try {
                    response = new StripeGateway(ConfigurationStatics.IsLiveInstallation ? liveSecretKey : testSecretKey).Post(
                        new ChargeStripeCustomer
                    {
                        Amount = (int)(amountInDollars.Value * 100), Currency = "usd", Description = description.Any() ? description : null, Card = token.Value
                    });
                }
                catch (StripeException e) {
                    if (e.Type == "card_error")
                    {
                        throw new DataModificationException(e.Message);
                    }
                    throw new ApplicationException("A credit-card charge failed.", e);
                }

                try {
                    var messageAndDestination = successHandler(response.Id, amountInDollars.Value);
                    if (messageAndDestination.Message.Any())
                    {
                        PageBase.AddStatusMessage(StatusMessageType.Info, messageAndDestination.Message);
                    }
                    successDestination = messageAndDestination.Destination;
                }
                catch (Exception e) {
                    throw new ApplicationException("An exception occurred after a credit card was charged.", e);
                }
            },
                actionGetter: () => new PostBackAction(successDestination));

            var hiddenFieldId = new HiddenFieldId();
            var hiddenFields  = new List <EtherealComponent>();

            FormState.ExecuteWithDataModificationsAndDefaultAction(
                postBack.ToCollection(),
                () => hiddenFields.Add(
                    new EwfHiddenField("", validationMethod: (postBackValue, validator) => token.Value = postBackValue.Value, id: hiddenFieldId).PageComponent));

            FormAction action = new PostBackFormAction(postBack);

            childGetter = () => {
                stripeCheckoutIncludeSetter();
                action.AddToPageIfNecessary();
                jsOpenStatements.AddStatementGetter(
                    () => {
                    var jsTokenHandler = "function( token, args ) { " + hiddenFieldId.GetJsValueModificationStatements("token.id") + " " + action.GetJsStatements() +
                                         " }";
                    return("StripeCheckout.open( { key: '" + (ConfigurationStatics.IsLiveInstallation ? livePublishableKey : testPublishableKey) + "', token: " +
                           jsTokenHandler + ", name: '" + name + "', description: '" + description + "', " +
                           (amountInDollars.HasValue ? "amount: " + amountInDollars.Value * 100 + ", " : "") + "email: '" +
                           (prefilledEmailAddressOverride ?? (AppTools.User == null ? "" : AppTools.User.Email)) + "' } );");
                });
                return(hiddenFields);
            };
        }