internal static void AddCheckBoxAttributes( WebControl checkBoxElement, Control checkBox, FormValue <bool> checkBoxFormValue, FormValue <CommonCheckBox> radioButtonFormValue, string radioButtonListItemId, FormAction action, bool autoPostBack, IEnumerable <string> onClickJsMethods) { checkBoxElement.Attributes.Add("type", checkBoxFormValue != null ? "checkbox" : "radio"); checkBoxElement.Attributes.Add("name", checkBoxFormValue != null ? checkBox.UniqueID : ((FormValue)radioButtonFormValue).GetPostBackValueKey()); if (radioButtonFormValue != null) { checkBoxElement.Attributes.Add("value", radioButtonListItemId ?? checkBox.UniqueID); } if (checkBoxFormValue != null ? checkBoxFormValue.GetValue(AppRequestState.Instance.EwfPageRequestState.PostBackValues) : radioButtonFormValue.GetValue(AppRequestState.Instance.EwfPageRequestState.PostBackValues) == checkBox) { checkBoxElement.Attributes.Add("checked", "checked"); } SubmitButton.EnsureImplicitSubmissionAction(checkBoxElement, action, false); var isSelectedRadioButton = radioButtonFormValue != null && radioButtonFormValue.GetValue(AppRequestState.Instance.EwfPageRequestState.PostBackValues) == checkBox; var postBackScript = autoPostBack && !isSelectedRadioButton?action.GetJsStatements() : ""; var customScript = StringTools.ConcatenateWithDelimiter("; ", onClickJsMethods.ToArray()); checkBoxElement.AddJavaScriptEventScript(JsWritingMethods.onclick, StringTools.ConcatenateWithDelimiter("; ", postBackScript, customScript)); }
internal void SetUpClickableControl(WebControl clickableControl) { if (resource == null && action == null && script == "") { return; } clickableControl.CssClass = clickableControl.CssClass.ConcatenateWithSpace("ewfClickable"); if (resource != null && EwfPage.Instance.IsAutoDataUpdater) { action = HyperlinkBehavior.GetHyperlinkPostBackAction(resource); resource = null; } Func <string> scriptGetter; if (resource != null) { scriptGetter = () => "location.href = '" + EwfPage.Instance.GetClientUrl(resource.GetUrl()) + "'; return false"; } else if (action != null) { action.AddToPageIfNecessary(); scriptGetter = () => action.GetJsStatements() + " return false"; } else { scriptGetter = () => script; } // Defer script generation until after all controls have IDs. EwfPage.Instance.PreRender += delegate { clickableControl.AddJavaScriptEventScript(JsWritingMethods.onclick, scriptGetter()); }; }
string ButtonBehavior.GetJsInitStatements(string id) { return("$( '#{0}' ).click( function() {{ {1} }} );".FormatWith(id, Action.GetJsStatements())); }
internal HyperlinkBehavior(ResourceInfo destination, string target, Func <string, string> actionStatementGetter) { this.destination = destination; Classes = destination?.AlternativeMode is NewContentResourceMode ? ActionComponentCssElementCreator.NewContentClass : ElementClassSet.Empty; Url = new Lazy <string>(() => destination != null ? destination.GetUrl(true, false, true) : ""); AttributeGetter = forNonHyperlinkElement => (destination != null && !forNonHyperlinkElement ? Tuple.Create("href", Url.Value).ToCollection() : Enumerable.Empty <Tuple <string, string> >()) .Concat( destination != null && target.Any() && !forNonHyperlinkElement ? Tuple.Create("target", target).ToCollection() : Enumerable.Empty <Tuple <string, string> >()) .Materialize(); var isPostBackHyperlink = destination != null && !(destination.AlternativeMode is DisabledResourceMode) && !target.Any() && EwfPage.Instance.IsAutoDataUpdater; FormAction postBackAction = null; string getActionInitStatements(string id, bool omitPreventDefaultStatement, string actionStatements) => "$( '#{0}' ).click( function( e ) {{ {1} }} );".FormatWith( id, (omitPreventDefaultStatement ? "" : "e.preventDefault();").ConcatenateWithSpace(actionStatements)); if (destination?.AlternativeMode is DisabledResourceMode disabledResourceMode) { IncludesIdAttribute = forNonHyperlinkElement => true; EtherealChildren = new ToolTip( (disabledResourceMode.Message.Any() ? disabledResourceMode.Message : Translation.ThePageYouRequestedIsDisabled).ToComponents(), out var toolTipInitStatementGetter).ToCollection(); JsInitStatementGetter = (id, forNonHyperlinkElement) => (forNonHyperlinkElement ? "" : getActionInitStatements(id, false, "") + " ") + toolTipInitStatementGetter(id); } else { IncludesIdAttribute = forNonHyperlinkElement => isPostBackHyperlink || (destination != null && (actionStatementGetter != null || forNonHyperlinkElement)); EtherealChildren = null; JsInitStatementGetter = (id, forNonHyperlinkElement) => { var actionStatements = isPostBackHyperlink ? postBackAction.GetJsStatements() : destination != null && actionStatementGetter != null?actionStatementGetter(Url.Value) : destination != null && forNonHyperlinkElement ? !target.Any() ? "window.location.href = '{0}';".FormatWith(Url.Value) : target == "_parent" ? "window.parent.location.href = '{0}';".FormatWith(Url.Value) : "window.open( '{0}', '{1}' );".FormatWith(Url.Value, target) : ""; return(actionStatements.Any() ? getActionInitStatements(id, forNonHyperlinkElement, actionStatements) : ""); }; } IsFocusable = destination != null; if (isPostBackHyperlink) { PostBackAdder = () => { postBackAction = GetHyperlinkPostBackAction(destination); postBackAction.AddToPageIfNecessary(); } } ; else { PostBackAdder = () => {} }; }
/// <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> /// Returns the JavaScript statements that should be executed on keypress to ensure that a form control will trigger the specified action when the enter key /// is pressed while the control has focus. If you specify the submit-button post-back, this method relies on HTML’s built-in implicit submission behavior, /// which will simulate a click on the submit button. /// </summary> internal static string GetImplicitSubmissionKeyPressStatements(FormAction action, bool forceJsHandling) { // EWF does not allow form controls to use HTML’s built-in implicit submission on a page with no submit button. There are two reasons for this. First, the // behavior of HTML’s implicit submission appears to be somewhat arbitrary when there is no submit button; see // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#implicit-submission. Second, we don’t want the implicit submission behavior of // form controls to unpredictably change if a submit button is added or removed. return(action is PostBackFormAction postBackAction && postBackAction.PostBack == PageBase.Current.SubmitButtonPostBack && !forceJsHandling ? "" : "if( e.which == 13 ) {{ {0} }}".FormatWith("e.preventDefault();".ConcatenateWithSpace(action?.GetJsStatements() ?? ""))); }
internal HyperlinkBehavior(ResourceInfo destination, bool disableAuthorizationCheck, string target, Func <string, string> actionStatementGetter) { hasDestination = destination != null; userCanNavigateToDestinationPredicate = () => !hasDestination || disableAuthorizationCheck || destination.UserCanAccessResource; var destinationAlternativeMode = hasDestination && !disableAuthorizationCheck ? destination.AlternativeMode : null; Classes = destinationAlternativeMode is NewContentResourceMode ? ActionComponentCssElementCreator.NewContentClass : ElementClassSet.Empty; Url = new Lazy <string>(() => hasDestination ? destination.GetUrl(!disableAuthorizationCheck, false) : ""); var isPostBackHyperlink = new Lazy <bool>( () => hasDestination && !(destinationAlternativeMode is DisabledResourceMode) && !target.Any() && PageBase.Current.IsAutoDataUpdater.Value); AttributeGetter = forNonHyperlinkElement => (hasDestination && !forNonHyperlinkElement ? new ElementAttribute("href", Url.Value).ToCollection() : Enumerable.Empty <ElementAttribute>()).Concat( hasDestination && target.Any() && !forNonHyperlinkElement ? new ElementAttribute("target", target).ToCollection() : Enumerable.Empty <ElementAttribute>()) .Concat( // for https://instant.page/ !isPostBackHyperlink.Value && destination is ResourceBase && !(destinationAlternativeMode is DisabledResourceMode) && !forNonHyperlinkElement ? new ElementAttribute("data-instant").ToCollection() : Enumerable.Empty <ElementAttribute>()) .Materialize(); FormAction postBackAction = null; string getActionInitStatements(string id, bool omitPreventDefaultStatement, string actionStatements) => "$( '#{0}' ).click( function( e ) {{ {1} }} );".FormatWith( id, (omitPreventDefaultStatement ? "" : "e.preventDefault();").ConcatenateWithSpace(actionStatements)); if (destinationAlternativeMode is DisabledResourceMode disabledResourceMode) { IncludesIdAttribute = forNonHyperlinkElement => true; EtherealChildren = new ToolTip( (disabledResourceMode.Message.Any() ? disabledResourceMode.Message : Translation.ThePageYouRequestedIsDisabled).ToComponents(), out var toolTipInitStatementGetter).ToCollection(); JsInitStatementGetter = (id, forNonHyperlinkElement) => (forNonHyperlinkElement ? "" : getActionInitStatements(id, false, "") + " ") + toolTipInitStatementGetter(id); } else { IncludesIdAttribute = forNonHyperlinkElement => isPostBackHyperlink.Value || (hasDestination && (actionStatementGetter != null || forNonHyperlinkElement)); EtherealChildren = null; JsInitStatementGetter = (id, forNonHyperlinkElement) => { var actionStatements = isPostBackHyperlink.Value ? postBackAction.GetJsStatements() : hasDestination && actionStatementGetter != null?actionStatementGetter(Url.Value) : hasDestination && forNonHyperlinkElement ? !target.Any() ? "window.location.href = '{0}';".FormatWith(Url.Value) : target == "_parent" ? "window.parent.location.href = '{0}';".FormatWith(Url.Value) : "window.open( '{0}', '{1}' );".FormatWith(Url.Value, target) : ""; return(actionStatements.Any() ? getActionInitStatements(id, forNonHyperlinkElement, actionStatements) : ""); }; } IsFocusable = hasDestination; PostBackAdder = () => { if (!isPostBackHyperlink.Value) { return; } var postBackId = PostBack.GetCompositeId("hyperlink", destination.GetUrl(), disableAuthorizationCheck.ToString()); postBackAction = new PostBackFormAction( PageBase.Current.GetPostBack(postBackId) ?? PostBack.CreateFull( id: postBackId, actionGetter: () => new PostBackAction(destination, authorizationCheckDisabledPredicate: effectiveDestination => disableAuthorizationCheck))); postBackAction.AddToPageIfNecessary(); }; }
void ControlTreeDataLoader.LoadData() { var isTextarea = rows > 1; textBox = new WebControl(isTextarea ? HtmlTextWriterTag.Textarea : HtmlTextWriterTag.Input); PreRender += delegate { if (!isTextarea) { textBox.Attributes.Add("type", masksCharacters ? "password" : "text"); } textBox.Attributes.Add("name", UniqueID); if (isTextarea) { textBox.Attributes.Add("rows", rows.ToString()); } if (maxLength.HasValue) { textBox.Attributes.Add("maxlength", maxLength.Value.ToString()); } if (readOnly) { textBox.Attributes.Add("readonly", "readonly"); } if (disableBrowserAutoComplete || autoCompleteService != null) { textBox.Attributes.Add("autocomplete", "off"); } if (suggestSpellCheck.HasValue) { textBox.Attributes.Add("spellcheck", suggestSpellCheck.Value.ToString().ToLower()); } var value = formValue.GetValue(AppRequestState.Instance.EwfPageRequestState.PostBackValues); var valueOrWatermark = watermarkText.Any() && !value.Any() ? watermarkText : value; if (isTextarea) { textBox.Controls.Add(new Literal { Text = HttpUtility.HtmlEncode(GetTextareaValue(valueOrWatermark)) }); } else if (!masksCharacters) { textBox.Attributes.Add("value", valueOrWatermark); } }; Controls.Add(textBox); if (watermarkText.Any()) { textBox.AddJavaScriptEventScript(JsWritingMethods.onfocus, "if( value == '" + watermarkText + "' ) value = ''"); textBox.AddJavaScriptEventScript(JsWritingMethods.onblur, "if( value == '' ) value = '" + watermarkText + "'"); EwfPage.Instance.ClientScript.RegisterOnSubmitStatement( GetType(), UniqueID + "watermark", "$( '#" + textBox.ClientID + "' ).filter( function() { return this.value == '" + watermarkText + "'; } ).val( '' )"); } if (!isTextarea || autoPostBack || (autoCompleteService != null && autoCompleteOption != AutoCompleteOption.NoPostBack)) { action.AddToPageIfNecessary(); } if (!isTextarea) { PreRender += delegate { SubmitButton.EnsureImplicitSubmissionAction( this, action, autoPostBack || (autoCompleteService != null && autoCompleteOption == AutoCompleteOption.PostBackOnTextChangeAndItemSelect)); } } ; if (autoPostBack || (autoCompleteService != null && autoCompleteOption == AutoCompleteOption.PostBackOnTextChangeAndItemSelect)) { PreRender += delegate { // Use setTimeout to prevent keypress and change from *both* triggering post-backs at the same time when Enter is pressed after a text change. textBox.AddJavaScriptEventScript(JsWritingMethods.onchange, "setTimeout( function() { " + action.GetJsStatements() + " }, 0 )"); } } ; if (ToolTip != null || ToolTipControl != null) { new ToolTip(ToolTipControl ?? EnterpriseWebFramework.Controls.ToolTip.GetToolTipTextControl(ToolTip), textBox); } } string ControlWithJsInitLogic.GetJsInitStatements() { var script = new StringBuilder(); if (watermarkText.Any()) { var restorationStatement = "$( '#" + textBox.ClientID + "' ).filter( function() { return this.value == ''; } ).val( '" + watermarkText + "' );"; // The first line is for bfcache browsers; the second is for all others. See http://stackoverflow.com/q/1195440/35349. script.Append("$( window ).on( 'pagehide', function() { " + restorationStatement + " } );"); script.Append(restorationStatement); } if (autoCompleteService != null) { const int delay = 250; // Default delay is 300 ms. const int minCharacters = 3; var autocompleteOptions = new List <Tuple <string, string> >(); autocompleteOptions.Add(Tuple.Create("delay", delay.ToString())); autocompleteOptions.Add(Tuple.Create("minLength", minCharacters.ToString())); autocompleteOptions.Add(Tuple.Create("source", "'" + autoCompleteService.GetUrl() + "'")); if (autoCompleteOption != AutoCompleteOption.NoPostBack) { var handler = "function( event, ui ) {{ $( '#{0}' ).val( ui.item.value ); {1} return false; }}".FormatWith(textBox.ClientID, action.GetJsStatements()); autocompleteOptions.Add(Tuple.Create("select", handler)); } script.Append( @"$( '#" + textBox.ClientID + "' ).autocomplete( {{ {0} }} );".FormatWith( autocompleteOptions.Select(o => "{0}: {1}".FormatWith(o.Item1, o.Item2)).GetCommaDelimitedStringFromCollection())); } return(script.ToString()); } FormValue FormValueControl.FormValue { get { return(formValue); } }
internal HyperlinkBehavior(ResourceInfo destination, string target) { this.destination = destination; Classes = destination?.AlternativeMode is NewContentResourceMode ? ActionComponentCssElementCreator.NewContentClass : ElementClassSet.Empty; Url = destination != null?destination.GetUrl(true, false, true) : ""; var isPostBackHyperlink = destination != null && !(destination.AlternativeMode is DisabledResourceMode) && !target.Any() && EwfPage.Instance.IsAutoDataUpdater; FormAction postBackAction = null; AttributeGetter = () => (Url.Any() ? Tuple.Create("href", Url).ToCollection() : Enumerable.Empty <Tuple <string, string> >()).Concat( target.Any() ? Tuple.Create("target", target).ToCollection() : Enumerable.Empty <Tuple <string, string> >()) .Concat( isPostBackHyperlink ? Tuple.Create(JsWritingMethods.onclick, postBackAction.GetJsStatements() + " return false").ToCollection() : Enumerable.Empty <Tuple <string, string> >()) .ToImmutableArray(); var disabledResourceMode = destination?.AlternativeMode as DisabledResourceMode; if (disabledResourceMode != null) { IncludeIdAttribute = true; Func <string, string> toolTipInitStatementGetter; EtherealChildren = new ToolTip( (disabledResourceMode.Message.Any() ? disabledResourceMode.Message : Translation.ThePageYouRequestedIsDisabled).ToComponents(), out toolTipInitStatementGetter).ToCollection(); JsInitStatementGetter = id => "$( '#{0}' ).click( function( e ) {{ e.preventDefault(); }} );".FormatWith(id) + toolTipInitStatementGetter(id); } else { EtherealChildren = ImmutableArray <EtherealComponent> .Empty; JsInitStatementGetter = id => ""; } if (isPostBackHyperlink) { PostBackAdder = () => { postBackAction = GetHyperlinkPostBackAction(destination); postBackAction.AddToPageIfNecessary(); } } ; else { PostBackAdder = () => { } }; }
/// <summary> /// Ensures that the specified control will trigger the specified action when the enter key is pressed while the control has focus. If you specify the /// submit-button post-back, this method relies on HTML's built-in implicit submission behavior, which will simulate a click on the submit button. /// </summary> /// <param name="control"></param> /// <param name="action">Do not pass null.</param> /// <param name="forceJsHandling"></param> /// <param name="predicate"></param> internal static void EnsureImplicitSubmissionAction(WebControl control, FormAction action, bool forceJsHandling, string predicate = "") { var postBackAction = action as PostBackFormAction; // EWF does not allow form controls to use HTML's built-in implicit submission on a page with no submit button. There are two reasons for this. First, the // behavior of HTML's implicit submission appears to be somewhat arbitrary when there is no submit button; see // https://html.spec.whatwg.org/multipage/forms.html#implicit-submission. Second, we don't want the implicit submission behavior of form controls to // unpredictably change if a submit button is added or removed. if (postBackAction == null || postBackAction.PostBack != EwfPage.Instance.SubmitButtonPostBack || forceJsHandling) { control.AddJavaScriptEventScript( JsWritingMethods.onkeypress, "if( event.which == 13 " + predicate.PrependDelimiter(" && ") + " ) { " + action.GetJsStatements() + " return false; }"); } }
void ControlTreeDataLoader.LoadData() { FormState.ExecuteWithDataModificationsAndDefaultAction( dataModifications, () => { if (TagKey == HtmlTextWriterTag.Button) { Attributes.Add("name", EwfPage.ButtonElementName); Attributes.Add("value", "v"); Attributes.Add("type", usesSubmitBehavior ? "submit" : "button"); } FormAction action = postBackAction; action.AddToPageIfNecessary(); if (ConfirmationWindowContentControl != null) { if (usesSubmitBehavior) { throw new ApplicationException("PostBackButton cannot be the submit button and also have a confirmation message."); } confirmationWindow = new ModalWindow(this, ConfirmationWindowContentControl, title: "Confirmation", postBack: postBackAction.PostBack); } else if (!usesSubmitBehavior) { PreRender += delegate { this.AddJavaScriptEventScript(JsWritingMethods.onclick, action.GetJsStatements() + " return false"); } } ; CssClass = CssClass.ConcatenateWithSpace("ewfClickable"); ActionControlStyle.SetUpControl(this, ""); }); }