protected KnockoutBindingGroup BuildControlKnockoutBinding() { var binding = new KnockoutBindingGroup(); binding.Add("maxItemsCount", this, MaxItemsCountProperty, () => { binding.Add("maxItemsCount", MaxItemsCount.ToString()); }); binding.Add("groupName", this, GroupNameProperty, () => { binding.Add("groupName", KnockoutHelper.MakeStringLiteral(GroupName)); }); binding.Add("allowedOperations", KnockoutHelper.MakeStringLiteral(AllowedOperations.ToString())); if (HasBinding(ItemDroppedProperty)) { var tempContainer = GetDataContextTarget(this, ItemDroppedProperty); var function = KnockoutHelper.GenerateClientPostBackExpression(nameof(ItemDropped), GetCommandBinding(ItemDroppedProperty), tempContainer, new PostbackScriptOptions() { ElementAccessor = CodeParameterAssignment.FromIdentifier("target") }); binding.Add("onItemDropped", $"function (target) {{ {function} }}"); } return(binding); }
protected override void AddAttributesToRender(IHtmlWriter writer, IDotvvmRequestContext context) { writer.AddAttribute("class", "code-editor"); writer.AddKnockoutDataBind("aceEditor", this, CodeProperty); writer.AddKnockoutDataBind("aceEditor-language", KnockoutHelper.MakeStringLiteral(Language.ToString().ToLower())); base.AddAttributesToRender(writer, context); }
protected override void AddAttributesToRender(IHtmlWriter writer, IDotvvmRequestContext context) { ExtraCssFileUrlProperty.IsSet(this); writer.AddAttribute("class", "dotvvm-crystal-report-viewer-container"); writer.AddAttribute("report-page-url", WebUtility.HtmlEncode(ReportPageUrl)); writer.AddAttribute("display-toolbar", DisplayToolbar.ToString()); writer.AddAttribute("display-page", DisplayPage.ToString()); writer.AddAttribute("display-statusbar", DisplayStatusbar.ToString()); writer.AddAttribute("best-fit-page", BestFitPage.ToString()); if (ExtraCssFileUrlProperty.IsSet(this)) { writer.AddAttribute("extra-css-file-url", WebUtility.HtmlEncode(ExtraCssFileUrl)); } if (WidthProperty.IsSet(this)) { writer.AddAttribute("width", Width); } if (HeightProperty.IsSet(this)) { writer.AddAttribute("height", Height); } writer.AddKnockoutDataBind("crystalReportFile", this, CrystalReportFileProperty, () => { writer.AddKnockoutDataBind("crystalReportFile", KnockoutHelper.MakeStringLiteral(CrystalReportFile)); }); base.AddAttributesToRender(writer, context); }
public string CompileBinding(string expression, Type[] contexts, Type expectedType) { var configuration = DotvvmTestHelper.CreateConfiguration(); configuration.RegisterApiClient(typeof(TestApiClient), "http://server/api", "./apiscript.js", "_api"); configuration.Markup.ImportedNamespaces.Add(new NamespaceImport("DotVVM.Framework.Tests.Binding")); var context = DataContextStack.Create(contexts.FirstOrDefault() ?? typeof(object), extensionParameters: new BindingExtensionParameter[] { new BindingPageInfoExtensionParameter(), }.Concat(configuration.Markup.DefaultExtensionParameters).ToArray()); for (int i = 1; i < contexts.Length; i++) { context = DataContextStack.Create(contexts[i], context); } var parser = new BindingExpressionBuilder(); var expressionTree = parser.ParseWithLambdaConversion(expression, context, BindingParserOptions.Create <ValueBindingExpression>(), expectedType); var jsExpression = configuration.ServiceProvider.GetRequiredService <StaticCommandBindingCompiler>().CompileToJavascript(context, expressionTree); return(KnockoutHelper.GenerateClientPostBackScript( "", new FakeCommandBinding(BindingPropertyResolvers.FormatJavascript(jsExpression, nullChecks: false), null), new Literal(), new PostbackScriptOptions( allowPostbackHandlers: false, returnValue: null, commandArgs: CodeParameterAssignment.FromIdentifier("commandArguments") ))); }
protected override void AddAttributesToRender(IHtmlWriter writer, IDotvvmRequestContext context) { writer.AddAttribute("type", "text"); writer.AddKnockoutDataBind("dotvvm-contrib-TypeAhead-DataSource", this, DataSourceProperty); writer.AddKnockoutDataBind("dotvvm-contrib-TypeAhead-SelectedValue", this, SelectedValueProperty); if (ItemValueBindingProperty.IsSet(this)) { writer.AddKnockoutDataBind("dotvvm-contrib-TypeAhead-ValueMember", ItemValueBinding.KnockoutExpression.ToDefaultString()); } if (ItemTextBindingProperty.IsSet(this)) { writer.AddKnockoutDataBind("dotvvm-contrib-TypeAhead-DisplayMember", ItemTextBinding.KnockoutExpression.ToDefaultString()); } var selectionChangedBinding = GetCommandBinding(SelectionChangedProperty); if (selectionChangedBinding != null) { writer.AddAttribute("onchange", KnockoutHelper.GenerateClientPostBackScript(nameof(SelectionChanged), selectionChangedBinding, this, isOnChange: true, useWindowSetTimeout: true)); } base.AddAttributesToRender(writer, context); }
protected override void AddAttributesToRender(IHtmlWriter writer, IDotvvmRequestContext context) { var script = KnockoutHelper.GenerateClientPostBackScript(nameof(Click), this.GetCommandBinding(ClickProperty), this, new PostbackScriptOptions(returnValue: null)); writer.AddAttribute("onclick", $"var promise = {script}; promise.then(a => this.innerText = a.commandResult || a)"); base.AddAttributesToRender(writer, context); }
public static ActiveDotvvmProperty RegisterCommandToAttribute <TDeclaringType>(string name, string attributeName) { return(DelegateActionProperty <object> .Register <TDeclaringType>(name, (writer, context, value, control) => { var binding = value as ICommandBinding; var script = KnockoutHelper.GenerateClientPostBackScript(name, binding, context, control); writer.AddAttribute(attributeName, script); })); }
public static ActiveDotvvmProperty RegisterCommandToAttribute <TDeclaringType>(string name, string attributeName) { return(DelegateActionProperty <ICommandBinding> .Register <TDeclaringType>(name, (writer, context, property, control) => { var binding = control.GetCommandBinding(property) ?? throw new Exception($"Command binding expression was expected in {property}."); var script = KnockoutHelper.GenerateClientPostBackScript(name, binding, control); writer.AddAttribute(attributeName, script); })); }
protected override void AddAttributesToRender(IHtmlWriter writer, IDotvvmRequestContext context) { writer.AddAttribute("onclick", KnockoutHelper.GenerateClientPostBackScript(nameof(Click), this.GetCommandBinding(ClickProperty), this, new PostbackScriptOptions( commandArgs: CodeParameterAssignment.FromExpression( new JsArrayExpression( new JsIdentifierExpression("prompt").Invoke(new JsLiteral("type something")) ) ) ))); }
protected override void AddAttributesToRender(IHtmlWriter writer, IDotvvmRequestContext context) { var parameter = Parameter.GetParametrizedKnockoutExpression(this); writer.AddAttribute("onclick", KnockoutHelper.GenerateClientPostBackScript(nameof(Click), this.GetCommandBinding(ClickProperty), this, new PostbackScriptOptions( commandArgs: new ParametrizedCode.Builder { "[", parameter, "]" }.Build(OperatorPrecedence.Max) ))); }
protected override void RenderContents(IHtmlWriter writer, IDotvvmRequestContext context) { var expr = SelectedKeyBinding.GetKnockoutBindingExpression(); for (int i = 0; i < Choices.Count; i++) { var key = KnockoutHelper.MakeStringLiteral(Choices[i].Key); writer.WriteKnockoutDataBindComment("if", $"ko.unwrap({expr}) === {key}"); templateHosts[i].Render(writer, context); writer.WriteKnockoutDataBindEndComment(); } }
public void CommandResolver_Valid_SimpleTest() { var path = new[] { ValueBindingExpression.CreateBinding <object>(bindingService, vm => ((Test1)vm[0]).A[0], (DataContextStack)null) }; var commandId = "someCommand"; var command = new CommandBindingExpression(bindingService, vm => { ((TestA)vm[0]).Test(((TestA)vm[0]).StringToPass, ((dynamic)vm[1]).NumberToPass); }, commandId); var testObject = new Test1 { A = new[] { new TestA() { StringToPass = "******" } }, NumberToPass = 16 }; var viewRoot = new DotvvmView() { DataContext = testObject }; viewRoot.SetBinding(Controls.Validation.TargetProperty, ValueBindingExpression.CreateBinding(bindingService, vm => vm.Last(), new ParametrizedCode("$root"))); var placeholder = new HtmlGenericControl("div"); placeholder.SetBinding(DotvvmBindableObject.DataContextProperty, path[0]); viewRoot.Children.Add(placeholder); var button = new Button(); button.SetBinding(ButtonBase.ClickProperty, command); placeholder.Children.Add(button); var resolver = new CommandResolver(); var context = new TestDotvvmRequestContext() { ViewModel = testObject, ModelState = new ModelState() }; context.ModelState.ValidationTargetPath = KnockoutHelper.GetValidationTargetExpression(button); resolver.GetFunction(viewRoot, context, path.Select(v => v.GetProperty <SimplePathExpressionBindingProperty>().Code.FormatKnockoutScript(button, v)).ToArray(), commandId, new Func <Type, object> [0]).Action(); Assert.AreEqual(testObject.NumberToPass, testObject.A[0].ResultInt); Assert.AreEqual(testObject.A[0].ResultString, testObject.A[0].ResultString); }
public void CommandResolver_Valid_SimpleTest() { var path = new[] { new ValueBindingExpression(vm => ((dynamic)vm[0]).A[0], "A()[0]") }; var commandId = "someCommand"; var command = new CommandBindingExpression(vm => ((TestA)vm[0]).Test(((TestA)vm[0]).StringToPass, ((dynamic)vm[1]).NumberToPass), commandId); var testObject = new { A = new[] { new TestA() { StringToPass = "******" } }, NumberToPass = 16 }; var viewRoot = new DotvvmView() { DataContext = testObject }; viewRoot.SetBinding(Validate.TargetProperty, new ValueBindingExpression(vm => vm.Last(), "$root")); var placeholder = new HtmlGenericControl("div"); placeholder.SetBinding(DotvvmBindableObject.DataContextProperty, path[0]); viewRoot.Children.Add(placeholder); var button = new Button(); button.SetBinding(ButtonBase.ClickProperty, command); placeholder.Children.Add(button); var resolver = new CommandResolver(); var context = new DotvvmRequestContext() { ViewModel = testObject }; context.ModelState.ValidationTargetPath = KnockoutHelper.GetValidationTargetExpression(button); resolver.GetFunction(viewRoot, context, path.Select(v => v.Javascript).ToArray(), commandId).Action(); Assert.AreEqual(testObject.NumberToPass, testObject.A[0].ResultInt); Assert.AreEqual(testObject.A[0].ResultString, testObject.A[0].ResultString); }
/// <summary> /// Finds the binding of the specified type on the specified viewmodel path. /// </summary> private FindBindingResult FindControlCommandBinding(string[] path, string commandId, DotvvmControl viewRootControl, DotvvmControl targetControl, string validationTargetPath) { // walk the control tree and find the path ControlCommandBindingExpression resultBinding = null; DotvvmProperty resultProperty = null; DotvvmControl resultControl = null; var walker = new ControlTreeWalker(viewRootControl); walker.ProcessControlTree((control) => { // compare path if (ViewModelPathComparer.AreEqual(path, walker.CurrentPathArray)) { // find bindings of current control var binding = control.GetAllBindings().Where(p => p.Value is ControlCommandBindingExpression) .FirstOrDefault(b => b.Value.BindingId == commandId); if (binding.Key != null) { // verify that the target control is the control command target if (control.GetClosestControlBindingTarget() == targetControl) { // we have found the binding, now get the validation path var currentValidationTargetPath = KnockoutHelper.GetValidationTargetExpression(control); if (currentValidationTargetPath == validationTargetPath) { // the validation path is equal, we have found the binding resultBinding = (ControlCommandBindingExpression)binding.Value; resultProperty = binding.Key; resultControl = control; } } } } }); return(new FindBindingResult { Property = resultProperty, Binding = resultBinding, Control = resultControl }); }
protected override void AddAttributesToRender(IHtmlWriter writer, IDotvvmRequestContext context) { writer.AddAttribute("type", "text"); writer.AddKnockoutDataBind("dotvvm-contrib-TypeAhead-DataSource", this, DataSourceProperty); writer.AddKnockoutDataBind("dotvvm-contrib-TypeAhead-SelectedValue", this, SelectedValueProperty); writer.AddKnockoutDataBind("dotvvm-contrib-TypeAhead-DisplayMember", KnockoutHelper.MakeStringLiteral(DisplayMember)); writer.AddKnockoutDataBind("dotvvm-contrib-TypeAhead-ValueMember", KnockoutHelper.MakeStringLiteral(ValueMember)); writer.AddKnockoutDataBind("dotvvm-contrib-TypeAhead-LimitToList", this, LimitToListProperty); var selectionChangedBinding = GetCommandBinding(SelectionChangedProperty); if (selectionChangedBinding != null) { writer.AddAttribute("onchange", KnockoutHelper.GenerateClientPostBackScript(nameof(SelectionChanged), selectionChangedBinding, this, isOnChange: true, useWindowSetTimeout: true)); } base.AddAttributesToRender(writer, context); }
protected override void AddAttributesToRender(IHtmlWriter writer, IDotvvmRequestContext context) { writer.AddStyleAttribute("display", "none"); writer.AddAttribute("class", "dotvvm__pwa__offline-handler", true); var onlinePageLoadBinding = GetCommandBinding(OnlinePageLoadProperty); if (onlinePageLoadBinding != null) { writer.AddAttribute("onlinepageload", KnockoutHelper.GenerateClientPostBackScript(nameof(OnlinePageLoad), onlinePageLoadBinding, this), true, ";"); } var offlinePageLoadBinding = GetCommandBinding(OfflinePageLoadProperty); if (offlinePageLoadBinding != null) { writer.AddAttribute("offlinepageload", KnockoutHelper.GenerateClientPostBackScript(nameof(OfflinePageLoad), offlinePageLoadBinding, this, new PostbackScriptOptions()), true, ";"); } base.AddAttributesToRender(writer, context); writer.AddKnockoutDataBind("dotvvm-pwa-offlineHandler", new KnockoutBindingGroup()); }
/// <summary> /// Finds the binding of the specified type on the specified viewmodel path. /// </summary> private FindBindingResult FindCommandBinding(string[] path, string commandId, DotvvmBindableObject viewRootControl, string validationTargetPath) { // walk the control tree and find the path CommandBindingExpression resultBinding = null; DotvvmBindableObject resultControl = null; DotvvmProperty resultProperty = null; var walker = new ControlTreeWalker(viewRootControl); walker.ProcessControlTree((control) => { // compare path if (resultBinding == null && ViewModelPathComparer.AreEqual(path, walker.CurrentPathArray)) { // find bindings of current control var binding = control.GetAllBindings() .FirstOrDefault(b => b.Value is CommandBindingExpression commandBinding && commandBinding.BindingId == commandId); if (binding.Key != null) { // we have found the binding, now get the validation path var currentValidationTargetPath = KnockoutHelper.GetValidationTargetExpression(control); if (currentValidationTargetPath == validationTargetPath) { // the validation path is equal, we have found the binding resultBinding = (CommandBindingExpression)binding.Value; resultControl = control; resultProperty = binding.Key; } } } }); return(new FindBindingResult { Binding = resultBinding, Control = resultControl, Property = resultProperty }); }
public void SetUp() { var viewContext = new ViewContext { HttpContext = new FakeHttpContext() }; var htmlHelper = new HtmlHelper<TestModel>(viewContext, new FakeViewDataContainer()); knockoutHelper = new KnockoutHelper<TestModel>(htmlHelper); }
protected override void AddAttributesToRender(IHtmlWriter writer, IDotvvmRequestContext context) { writer.AddKnockoutDataBind("doneTyping", "function () { " + KnockoutHelper.GenerateClientPostBackScript(nameof(DoneTyping), GetCommandBinding(DoneTypingProperty), this, true, null, false, "$element") + " } "); writer.AddAttribute("delay", SearchDelayInMs.ToString()); base.AddAttributesToRender(writer, context); }
protected override void AddAttributesToRender(IHtmlWriter writer, IDotvvmRequestContext context) { context.ResourceManager.AddCurrentCultureGlobalizationResource(); IValueBinding dateBinding = null; foreach (var item in Properties) { if (item.Key == DateProperty) { dateBinding = item.Value as IValueBinding; } } if (dateBinding == null) { var expression = dateBinding.GetKnockoutBindingExpression(this); expression = "dotvvm.globalize.formatString(" + JsonConvert.ToString("d.M.yyyy") + ", " + expression + ")"; writer.AddKnockoutDataBind("dotvvm-contrib-BootstrapDatepicker", expression); } else { writer.AddKnockoutDataBind("dotvvm-contrib-BootstrapDatepicker", this, DateProperty, renderEvenInServerRenderingMode: true); } if (!string.IsNullOrWhiteSpace(Language)) { writer.AddAttribute("data-date-language", Language); } var activeTabChangedBinding = GetCommandBinding(ChangedProperty); if (activeTabChangedBinding != null) { writer.AddAttribute("data-dotvvm-contrib-BootstrapDatepicker-changed", KnockoutHelper.GenerateClientPostBackScript(nameof(Changed), activeTabChangedBinding, this, true, null)); } base.AddAttributesToRender(writer, context); }
/// <summary> /// Finds the binding of the specified type on the specified viewmodel path. /// </summary> /// <param name="path">DataContext path of the binding</param> /// <param name="commandId">Id of the binding</param> /// <param name="viewRootControl">ViewRootControl of the binding</param> /// <param name="targetControl">Target control of the binding, null if not finding control command binding</param> /// <param name="validationTargetPath">Validation path of the binding</param> /// <param name="findControl">Determinate whether finding control command binding or not</param> /// <returns></returns> private FindBindingResult FindCommandBinding(string[] path, string commandId, DotvvmBindableObject viewRootControl, DotvvmBindableObject targetControl, string validationTargetPath, bool findControl) { // walk the control tree and find the path CommandBindingExpression resultBinding = null; DotvvmBindableObject resultControl = null; DotvvmProperty resultProperty = null; bool checkControl; bool bindingInPath = false; var candidateBindings = new Dictionary <string, CandidateBindings>(); string errorMessage = null; var walker = new ControlTreeWalker(viewRootControl); walker.ProcessControlTree((control) => { if (resultBinding == null) { // find bindings of current control var bindings = control.GetAllBindings() .Where(b => b.Value is CommandBindingExpression); foreach (var binding in bindings) { var wrongExceptionPropertyKeys = new List <string>(); var correctExceptionPropertyKeys = new List <string>(); var infoMessage = new StringBuilder(); // checking path if (!ViewModelPathComparer.AreEqual(path, walker.CurrentPathArray)) { wrongExceptionPropertyKeys.Add("DataContext path"); infoMessage.Append( $"Expected DataContext path: '{string.Join("/", path)}' Command binding DataContext path: '{string.Join("/", walker.CurrentPathArray)}'"); } else { //Found a binding in DataContext bindingInPath = true; correctExceptionPropertyKeys.Add("DataContext path"); } //checking binding id if (((CommandBindingExpression)binding.Value).BindingId != commandId) { wrongExceptionPropertyKeys.Add("binding id"); } else { correctExceptionPropertyKeys.Add("binding id"); } //checking validation path var currentValidationTargetPath = KnockoutHelper.GetValidationTargetExpression(control); if (currentValidationTargetPath != validationTargetPath) { wrongExceptionPropertyKeys.Add("validation path"); infoMessage.Append($"Expected validation path: '{string.Join("/", validationTargetPath)}' Command binding validation path: '{string.Join("/", currentValidationTargetPath)}'"); } else { correctExceptionPropertyKeys.Add("validation path"); } //If finding control command binding checks if the binding is control otherwise always true checkControl = !findControl || control.GetClosestControlBindingTarget() == targetControl; if (!wrongExceptionPropertyKeys.Any() && checkControl) { //correct binding found resultBinding = (CommandBindingExpression)binding.Value; resultControl = control; resultProperty = binding.Key; } else if (wrongExceptionPropertyKeys.Any()) { var exceptionPropertyKey = (findControl && checkControl ? "Control command bindings with wrong " : "Command bindings with wrong ") + string.Join(", ", wrongExceptionPropertyKeys) + (correctExceptionPropertyKeys.Any() ? " and correct " + string.Join(", ", correctExceptionPropertyKeys) : "") + ":"; if (!candidateBindings.ContainsKey(exceptionPropertyKey)) { candidateBindings.Add(exceptionPropertyKey, new CandidateBindings()); } candidateBindings[exceptionPropertyKey] .AddBinding(new KeyValuePair <string, IBinding>(infoMessage.ToString(), binding.Value)); } else { errorMessage = "Invalid command invocation (the binding is not control command binding)"; } } } }); return(new FindBindingResult { ErrorMessage = bindingInPath ? errorMessage : "Nothing was found in found inside specified DataContext check if ViewModel is populated", CandidateBindings = candidateBindings, Binding = resultBinding, Control = resultControl, Property = resultProperty }); }