DotvvmChildEventCallback

Details

diff --git a/src/Web/Controls/ConfirmationModal/ConfirmationModal.cs b/src/Web/Controls/ConfirmationModal/ConfirmationModal.cs
new file mode 100644
index 0000000..419fbae
--- /dev/null
+++ b/src/Web/Controls/ConfirmationModal/ConfirmationModal.cs
@@ -0,0 +1,131 @@
+namespace Web.Controls.ConfirmationModal
+{
+    using DotVVM.Framework.Binding;
+    using DotVVM.Framework.Binding.Expressions;
+    using DotVVM.Framework.Controls;
+    using System.Threading.Tasks;
+
+    public class ConfirmationModal : DotvvmMarkupControl
+    {
+        public bool ButtonsOnly
+        {
+            get { return (bool)GetValue(ButtonsOnlyProperty); }
+            set { SetValue(ButtonsOnlyProperty, value); }
+        }
+        public static readonly DotvvmProperty ButtonsOnlyProperty
+            = DotvvmProperty.Register<bool, ConfirmationModal>(c => c.ButtonsOnly, true);
+
+        public Command CancelButtonCommand
+        {
+            get { return (Command)GetValue(CancelButtonCommandProperty); }
+            set
+            {
+                SetValue(CancelButtonCommandProperty, value);
+            }
+        }
+        public static readonly DotvvmProperty CancelButtonCommandProperty
+            = DotvvmProperty.Register<Command, ConfirmationModal>(c => c.CancelButtonCommand, null);
+
+        public string CancelButtonText
+        {
+            get { return (string)GetValue(CancelButtonTextProperty); }
+            set { SetValue(CancelButtonTextProperty, value); }
+        }
+        public static readonly DotvvmProperty CancelButtonTextProperty
+            = DotvvmProperty.Register<string, ConfirmationModal>(c => c.CancelButtonText, "No");
+
+        public string CancelButtonType
+        {
+            get { return (string)GetValue(CancelButtonTypeProperty); }
+            set { SetValue(CancelButtonTypeProperty, value); }
+        }
+        public static readonly DotvvmProperty CancelButtonTypeProperty
+            = DotvvmProperty.Register<string, ConfirmationModal>(c => c.CancelButtonType, "Link");
+
+
+
+        public string CheckboxText
+        {
+            get { return (string)GetValue(CheckboxTextProperty); }
+            set { SetValue(CheckboxTextProperty, value); }
+        }
+        public static readonly DotvvmProperty CheckboxTextProperty
+            = DotvvmProperty.Register<string, ConfirmationModal>(c => c.CheckboxText, null);
+
+        public bool CheckboxValue { get; set; }
+
+        public string ModalHeader
+        {
+            get { return (string)GetValue(ModalHeaderProperty); }
+            set { SetValue(ModalHeaderProperty, value); }
+        }
+        public static readonly DotvvmProperty ModalHeaderProperty
+            = DotvvmProperty.Register<string, ConfirmationModal>(c => c.ModalHeader, "Ams Message");
+
+        public string ModalText
+        {
+            get { return (string)GetValue(ModalTextProperty); }
+            set { SetValue(ModalTextProperty, value); }
+        }
+        public static readonly DotvvmProperty ModalTextProperty
+            = DotvvmProperty.Register<string, ConfirmationModal>(c => c.ModalText, null);
+
+        public bool ModalVisible
+        {
+            get { return (bool)GetValue(ModalVisibleProperty); }
+            set { SetValue(ModalVisibleProperty, value); }
+        }
+        public static readonly DotvvmProperty ModalVisibleProperty
+            = DotvvmProperty.Register<bool, ConfirmationModal>(c => c.ModalVisible);
+
+        public Command SubmitButtonCommand
+        {
+            get { return (Command)GetValue(SubmitButtonCommandProperty); }
+            set
+            {
+                SetValue(SubmitButtonCommandProperty, value);
+            }
+        }
+        public static readonly DotvvmProperty SubmitButtonCommandProperty
+            = DotvvmProperty.Register<Command, ConfirmationModal>(c => c.SubmitButtonCommand, null);
+
+        public string SubmitButtonText
+        {
+            get { return (string)GetValue(SubmitButtonTextProperty); }
+            set { SetValue(SubmitButtonTextProperty, value); }
+        }
+        public static readonly DotvvmProperty SubmitButtonTextProperty
+            = DotvvmProperty.Register<string, ConfirmationModal>(c => c.SubmitButtonText, "Yes");
+
+
+        public string SubmitButtonType
+        {
+            get { return (string)GetValue(SubmitButtonTypeProperty); }
+            set { SetValue(SubmitButtonTypeProperty, value); }
+        }
+        public static readonly DotvvmProperty SubmitButtonTypeProperty
+            = DotvvmProperty.Register<string, ConfirmationModal>(c => c.SubmitButtonType, "Light");
+
+
+        public async Task SubmitCommand()
+        {
+            var binding = GetCommandBinding(SubmitButtonCommandProperty);
+
+            SetValueToSource(ModalVisibleProperty, false);
+            if (binding == null)
+                return;
+
+            await SubmitButtonCommand.Invoke();
+        }
+
+        public async Task CancelCommand()
+        {
+            var binding = GetCommandBinding(CancelButtonCommandProperty);
+            SetValueToSource(ModalVisibleProperty, false);
+            if (binding == null)
+                return;
+
+            await CancelButtonCommand.Invoke();
+        }
+    }
+}
diff --git a/src/Web/Controls/ConfirmationModal/ConfirmationModal.dotcontrol b/src/Web/Controls/ConfirmationModal/ConfirmationModal.dotcontrol
new file mode 100644
index 0000000..84936ba
--- /dev/null
+++ b/src/Web/Controls/ConfirmationModal/ConfirmationModal.dotcontrol
@@ -0,0 +1,69 @@
+@viewModel System.Object, mscorlib
+@baseType Web.Controls.ConfirmationModal.ConfirmationModal, Web
+
+<span class="cl-modal-confirmation" IncludeInPage="{controlProperty: ModalVisible}">
+    <bs:ModalDialog CloseOnEscape="false" CloseOnBackdropClick="false" IsDisplayed="{controlProperty: ModalVisible}" class="test" HeaderText="{{controlProperty: ModalHeader}}">
+        <ContentTemplate>
+            {{controlProperty: ModalText}}
+            <br />
+            <br />
+            <div Visible="{controlProperty: !ButtonsOnly}">
+                <bs:Checkbox Checked="{controlProperty: false}" onclick="onConfirmationCheckboxClicked(this)" Text="{controlProperty: CheckboxText}" />
+            </div>
+        </ContentTemplate>
+        <FooterTemplate>
+            <span class="modal-footer-container">
+                <span IncludeInPage="{controlProperty: SubmitButtonType == "Light"}">
+                    <bs:Button Click="{controlCommand: SubmitCommand()}" disabled onclick="removeConfirmationModal(this)" Text="{controlProperty: SubmitButtonText}" Type="Light" Visible="{controlProperty: !ButtonsOnly}" />
+                    <bs:Button Click="{controlCommand: SubmitCommand()}" onclick="removeConfirmationModal(this)" Text="{controlProperty: SubmitButtonText}" Type="Light" Visible="{controlProperty: ButtonsOnly}" />
+                </span>
+                <span IncludeInPage="{controlProperty: SubmitButtonType == "Secondary"}">
+                    <bs:Button Click="{controlCommand: SubmitCommand()}" disabled onclick="removeConfirmationModal(this)" Text="{controlProperty: SubmitButtonText}" Type="Secondary" Visible="{controlProperty: !ButtonsOnly}" />
+                    <bs:Button Click="{controlCommand: SubmitCommand()}" onclick="removeConfirmationModal(this)" Text="{controlProperty: SubmitButtonText}" Type="Secondary" Visible="{controlProperty: ButtonsOnly}" />
+                </span>
+                <span IncludeInPage="{controlProperty: SubmitButtonType == "Success"}">
+                    <bs:Button Click="{controlCommand: SubmitCommand()}" disabled onclick="removeConfirmationModal(this)" Text="{controlProperty: SubmitButtonText}" Type="Success" Visible="{controlProperty: !ButtonsOnly}" />
+                    <bs:Button Click="{controlCommand: SubmitCommand()}" onclick="removeConfirmationModal(this)" Text="{controlProperty: SubmitButtonText}" Type="Success" Visible="{controlProperty: ButtonsOnly}" />
+                </span>
+                <span IncludeInPage="{controlProperty: SubmitButtonType == "Danger"}">
+                    <bs:Button Click="{controlCommand: SubmitCommand()}" disabled onclick="removeConfirmationModal(this)" Text="{controlProperty: SubmitButtonText}" Type="Danger" Visible="{controlProperty: !ButtonsOnly}" />
+                    <bs:Button Click="{controlCommand: SubmitCommand()}" onclick="removeConfirmationModal(this)" Text="{controlProperty: SubmitButtonText}" Type="Danger" Visible="{controlProperty: ButtonsOnly}" />
+                </span>
+                <span IncludeInPage="{controlProperty: SubmitButtonType == "Warning"}">
+                    <bs:Button Click="{controlCommand: SubmitCommand()}" disabled onclick="removeConfirmationModal(this)" Text="{controlProperty: SubmitButtonText}" Type="Warning" Visible="{controlProperty: !ButtonsOnly}" />
+                    <bs:Button Click="{controlCommand: SubmitCommand()}" onclick="removeConfirmationModal(this)" Text="{controlProperty: SubmitButtonText}" Type="Warning" Visible="{controlProperty: ButtonsOnly}" />
+                </span>
+                <span IncludeInPage="{controlProperty: SubmitButtonType == "Dark"}">
+                    <bs:Button Click="{controlCommand: SubmitCommand()}" disabled onclick="removeConfirmationModal(this)" Text="{controlProperty: SubmitButtonText}" Type="Dark" Visible="{controlProperty: !ButtonsOnly}" />
+                    <bs:Button Click="{controlCommand: SubmitCommand()}" onclick="removeConfirmationModal(this)" Text="{controlProperty: SubmitButtonText}" Type="Dark" Visible="{controlProperty: ButtonsOnly}" />
+                </span>
+                <span IncludeInPage="{controlProperty: SubmitButtonType == "Link"}">
+                    <bs:Button Click="{controlCommand: SubmitCommand()}" disabled onclick="removeConfirmationModal(this)" Text="{controlProperty: SubmitButtonText}" Type="Link" Visible="{controlProperty: !ButtonsOnly}" />
+                    <bs:Button Click="{controlCommand: SubmitCommand()}" onclick="removeConfirmationModal(this)" Text="{controlProperty: SubmitButtonText}" Type="Link" Visible="{controlProperty: ButtonsOnly}" />
+                </span>
+                <span IncludeInPage="{controlProperty: CancelButtonType == "Light"}">
+                    <bs:Button Click="{controlCommand: CancelCommand()}" onclick="removeConfirmationModal(this)" Type="{value: "Light"}" Text="{controlProperty: CancelButtonText}" />
+                </span>
+                <span IncludeInPage="{controlProperty: CancelButtonType == "Secondary"}">
+                    <bs:Button Click="{controlCommand: CancelCommand()}" onclick="removeConfirmationModal(this)" Type="{value: "Secondary"}" Text="{controlProperty: CancelButtonText}" />
+                </span>
+                <span IncludeInPage="{controlProperty: CancelButtonType == "Success"}">
+                    <bs:Button Click="{controlCommand: CancelCommand()}" onclick="removeConfirmationModal(this)" Type="{value: "Success"}" Text="{controlProperty: CancelButtonText}" />
+                </span>
+                <span IncludeInPage="{controlProperty: CancelButtonType == "Danger"}">
+                    <bs:Button Click="{controlCommand: CancelCommand()}" onclick="removeConfirmationModal(this)" Type="{value: "Danger"}" Text="{controlProperty: CancelButtonText}" />
+                </span>
+                <span IncludeInPage="{controlProperty: CancelButtonType == "Warning"}">
+                    <bs:Button Click="{controlCommand: CancelCommand()}" onclick="removeConfirmationModal(this)" Type="{value: "Warning"}" Text="{controlProperty: CancelButtonText}" />
+                </span>
+                <span IncludeInPage="{controlProperty: CancelButtonType == "Dark"}">
+                    <bs:Button Click="{controlCommand: CancelCommand()}" onclick="removeConfirmationModal(this)" Type="{value: "Dark"}" Text="{controlProperty: CancelButtonText}" />
+                </span>
+                <span IncludeInPage="{controlProperty: CancelButtonType == "Link"}">
+                    <bs:Button Click="{controlCommand: CancelCommand()}" onclick="removeConfirmationModal(this)" Type="{value: "Link"}" Text="{controlProperty: CancelButtonText}" />
+                </span>
+            </span>
+        </FooterTemplate>
+    </bs:ModalDialog>
+</span>
+<dot:RequiredResource Name="ConfirmationModalJs" />
diff --git a/src/Web/Controls/ConfirmationModal/ConfirmationModalConfigurationExtensions.cs b/src/Web/Controls/ConfirmationModal/ConfirmationModalConfigurationExtensions.cs
new file mode 100644
index 0000000..270216a
--- /dev/null
+++ b/src/Web/Controls/ConfirmationModal/ConfirmationModalConfigurationExtensions.cs
@@ -0,0 +1,25 @@
+namespace Web.Controls.ConfirmationModal
+{
+    using DotVVM.Framework.Configuration;
+    using DotVVM.Framework.ResourceManagement;
+    using Helper;
+
+    public static class ConfirmationModalConfigurationExtensions
+    {
+        public static void AddConfirmationModalConfiguration(this DotvvmConfiguration config)
+        {
+            config.Markup.Controls.Add(new DotvvmControlConfiguration()
+            {
+                Assembly = typeof(ConfirmationModal).Assembly.GetName().Name,
+                Namespace = typeof(ConfirmationModal).Namespace,
+                TagPrefix = Constants.TagPrefix
+            });
+
+            config.Resources.Register("ConfirmationModalJs", new ScriptResource()
+            {
+                Dependencies = new[] { "jquery" },
+                Location = new UrlResourceLocation("~/wwwroot/js/controls/confirmationModal/confirmationModal.js")
+            });
+        }
+    }
+}
diff --git a/src/Web/DotvvmStartup.cs b/src/Web/DotvvmStartup.cs
index 5f7933a..9728645 100644
--- a/src/Web/DotvvmStartup.cs
+++ b/src/Web/DotvvmStartup.cs
@@ -1,5 +1,6 @@
 namespace Web
 {
+    using Controls.ConfirmationModal;
     using DotVVM.Framework.Configuration;
     using DotVVM.Framework.Controls.Bootstrap4;
     using DotVVM.Framework.ResourceManagement;
@@ -33,6 +34,8 @@ namespace Web
         #region Private Methods
         private void ConfigureControls(DotvvmConfiguration config, string applicationPath)
         {
+            config.AddConfirmationModalConfiguration();
+            config.Markup.AutoDiscoverControls(new DefaultControlRegistrationStrategy(config, Constants.TagPrefix, "Controls"));
         }
 
         private void ConfigureResources(DotvvmConfiguration config, string applicationPath)
@@ -43,6 +46,7 @@ namespace Web
 
         private void ConfigureRoutes(DotvvmConfiguration config, string applicationPath)
         {
+            config.RouteTable.Add("Debug", "debug", "Views/debug.dothtml");
             config.RouteTable.Add("Default", "", "Views/default.dothtml");
             //config.RouteTable.AutoDiscoverRoutes(new DefaultRouteStrategy(config));
         }
@@ -68,6 +72,11 @@ namespace Web
 
         private void RegisterJavascript(DotvvmConfiguration config)
         {
+            config.Resources.Register("ConfirmationModalJs", new ScriptResource()
+            {
+                Dependencies = new[] { "jquery" },
+                Location = new UrlResourceLocation("~/wwwroot/js/controls/confirmationModal/confirmationModal.js")
+            });
         }
         #endregion
     }
diff --git a/src/Web/Helper/Constants.cs b/src/Web/Helper/Constants.cs
index 5c7c657..a0a7827 100644
--- a/src/Web/Helper/Constants.cs
+++ b/src/Web/Helper/Constants.cs
@@ -3,5 +3,6 @@ namespace Web.Helper
     public static class Constants
     {
         public const string DefaultTemporaryStoragePath = "App_Data\\temporary";
+        public const string TagPrefix = "cl";
     }
 }
diff --git a/src/Web/ViewModels/DebugViewModel.cs b/src/Web/ViewModels/DebugViewModel.cs
new file mode 100644
index 0000000..286e18a
--- /dev/null
+++ b/src/Web/ViewModels/DebugViewModel.cs
@@ -0,0 +1,21 @@
+namespace Web.ViewModels
+{
+    using DotVVM.Framework.ViewModel;
+    using System.Threading.Tasks;
+
+    public class DebugViewModel : DotvvmViewModelBase
+    {
+        public string Message { get; set; }
+        public bool Show { get; set; }
+
+        public void OnShowClick()
+        {
+            Show = true;
+        }
+
+        public async Task OnSubmitClick()
+        {
+            await Task.CompletedTask;
+        }
+    }
+}
diff --git a/src/Web/ViewModels/DefaultViewModel.cs b/src/Web/ViewModels/DefaultViewModel.cs
index 99daed8..e8e77bd 100644
--- a/src/Web/ViewModels/DefaultViewModel.cs
+++ b/src/Web/ViewModels/DefaultViewModel.cs
@@ -2,6 +2,7 @@ namespace Web.ViewModels
 {
     using System;
     using System.Collections.Generic;
+    using System.Threading.Tasks;
     using static DefaultViewModelEvents;
 
     public static class DefaultViewModelEvents
@@ -68,8 +69,11 @@ namespace Web.ViewModels
     {
         public ToggleNext ToggleNext;
 
+        public string ConfirmationMessage { get; set; }
         public bool IsInitialized { get; set; }
         public bool IsNextEnabled { get; set; }
+        
+        public bool ShowConfirmationModal { get; set; }
 
         public void Initialize(ToggleNext toggleNext)
         {
@@ -77,10 +81,21 @@ namespace Web.ViewModels
             IsInitialized = true;
         }
 
-        public void OnContinueChanged()
+        public void OnConfirmationShowClick()
         {
-            ToggleNext?.Invoke(IsNextEnabled);
+            ShowConfirmationModal = true;
         }
+
+        public void OnConfirmationSubmitClick()
+        {
+            IsNextEnabled = true;
+            ToggleNext.Invoke(IsNextEnabled);
+        }
+
+        //public void OnContinueChanged()
+        //{
+        //    ToggleNext?.Invoke(IsNextEnabled);
+        //}
     }
     #endregion
 
diff --git a/src/Web/Views/Debug.dothtml b/src/Web/Views/Debug.dothtml
new file mode 100644
index 0000000..eb2838f
--- /dev/null
+++ b/src/Web/Views/Debug.dothtml
@@ -0,0 +1,23 @@
+@viewModel Web.ViewModels.DebugViewModel, Web
+
+<!doctype html>
+<html lang="en-us">
+<head>
+    <meta charset="utf-8">
+    <title>Debug</title>
+    <meta name="description" content="">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <link rel="icon" href="/favicon.ico" sizes="any">
+    <meta name="theme-color" content="#fafafa">
+    <dot:RequiredResource Name="Styles" />
+</head>
+<body Visible="{value: _page.EvaluatingOnClient}">
+    <cl:ConfirmationModal ButtonsOnly="false"
+                          CheckboxText="Do you wish to enable next button?"
+                          ModalHeader="Next Button"
+                          ModalText="{value: Message}"
+                          ModalVisible="{value: Show}"
+                          SubmitButtonCommand="{command: OnSubmitClick()}"></cl:ConfirmationModal>    
+    <bs:Button Click="{command: OnShowClick()}" IncludeInPage="{value: !Show}" Text="Confirm" Type="Danger" />
+</body>
+</html>
diff --git a/src/Web/Views/Default.dothtml b/src/Web/Views/Default.dothtml
index fd71208..bf86c98 100644
--- a/src/Web/Views/Default.dothtml
+++ b/src/Web/Views/Default.dothtml
@@ -47,6 +47,12 @@
             <div class="col-md-12">
                 <div IncludeInPage="{value: Wizard.Step == 1}">
                     <div DataContext="{value: First}">
+                        <cl:ConfirmationModal ButtonsOnly="false"
+                                              CheckboxText="Do you wish to enable next button?"
+                                              ModalHeader="Next Button"
+                                              ModalText="{value: ConfirmationMessage}"
+                                              ModalVisible="{value: ShowConfirmationModal}"
+                                              SubmitButtonCommand="{command: OnConfirmationSubmitClick()}" />
                         <bs:Card>
                             <FooterTemplate>
                                 <footer class="blockquote-footer">Charles Dickens: <cite title="Source Title">A Tale of Two Cities</cite></footer>
@@ -65,7 +71,8 @@
                                         degree of comparison only.
                                     </p>
                                 </blockquote>
-                                <bs:CheckBox Checked="{value: IsNextEnabled}" Changed="{command: OnContinueChanged()}" IsInline="true" Text="Continue" />
+                                <%--<bs:CheckBox Checked="{value: IsNextEnabled}" Changed="{command: OnContinueChanged()}" IsInline="true" Text="Continue" />--%>
+                                <bs:Button Click="{command: OnConfirmationShowClick()}" IncludeInPage="{value: !ShowConfirmationModal}" Text="Confirm" />
                             </bs:CardBody>
                         </bs:Card>
                     </div>
@@ -97,7 +104,7 @@
                                     </p>
                                 </blockquote>
                             </bs:CardBody>
-                        </bs:Card>                        
+                        </bs:Card>
                     </div>
                 </div>
             </div>
diff --git a/src/Web/Web.csproj b/src/Web/Web.csproj
index 9032ab0..45b43f9 100644
--- a/src/Web/Web.csproj
+++ b/src/Web/Web.csproj
@@ -191,15 +191,19 @@
     <Reference Include="System.Xml.Linq" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="Controls\ConfirmationModal\ConfirmationModal.cs" />
+    <Compile Include="Controls\ConfirmationModal\ConfirmationModalConfigurationExtensions.cs" />
     <Compile Include="Helper\Constants.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Startup.cs" />
     <Compile Include="DotVvmStartup.cs" />
+    <Compile Include="ViewModels\DebugViewModel.cs" />
     <Compile Include="ViewModels\DefaultViewModel.cs" />
     <Compile Include="ViewModels\SiteViewModel.cs" />
     <Compile Include="Models\ToastType.cs" />
   </ItemGroup>
   <ItemGroup>
+    <Content Include="wwwroot\js\controls\confirmationModal\confirmationModal.js" />
     <Content Include="favicon.ico" />
     <Content Include="wwwroot\js\toastr\font-awesome-icons.css" />
     <Content Include="wwwroot\js\toastr\toastr.options.js" />
@@ -227,9 +231,11 @@
     <Content Include="wwwroot\js\toastr\toastr.css" />
     <Content Include="wwwroot\js\toastr\toastr.min.css" />
     <Content Include="wwwroot\js\toastr\toastr.min.js" />
+    <Content Include="Controls\ConfirmationModal\ConfirmationModal.dotcontrol" />
     <None Include="packages.config" />
     <Content Include="Views\Site.dotmaster" />
     <Content Include="Views\Default.dothtml" />
+    <Content Include="Views\Debug.dothtml" />
     <None Include="Web.Debug.config">
       <DependentUpon>Web.config</DependentUpon>
     </None>
diff --git a/src/Web/wwwroot/js/controls/confirmationModal/confirmationModal.js b/src/Web/wwwroot/js/controls/confirmationModal/confirmationModal.js
new file mode 100644
index 0000000..b6ed3a4
--- /dev/null
+++ b/src/Web/wwwroot/js/controls/confirmationModal/confirmationModal.js
@@ -0,0 +1,14 @@
+function onConfirmationCheckboxClicked(element) {
+    var checkbox = $(element).find('input');
+    var button = checkbox.parent().parent().parent().parent().find('.modal-footer').find('input:first');
+
+    if (checkbox.is(":checked")) {
+        button.removeAttr('disabled');
+    } else {
+        button.attr('disabled', 'disabled');
+    };
+};
+
+function removeConfirmationModal(element) {
+    $('.modal-backdrop.fade.show').remove();
+};