using CefSharp; using CefSharp.WinForms; using System; using System.Diagnostics; using System.Drawing; using System.IO; using System.Windows.Forms; using System.Xml; using TradeIdeas.Logging; namespace TradeIdeas.TIProGUI { public partial class ContactSupportForm : Form, ISaveLayout { private ChromiumWebBrowser _webBrowser; private ContactSupportJsInterops _contactSupportJsInterops = new ContactSupportJsInterops(); public WindowIconCache WindowIconCache => new WindowIconCache("CONTACT_SUPPORT_FORM"); public bool Pinned { get; set; } = false; public ContactSupportForm() { InitializeComponent(); // Initialize the browser. InitializeChromium(); Controls.Add(_webBrowser); LoadContactSupportTemplate(); } /// /// Initialize the Chromium browser. /// private void InitializeChromium() { try { Debug.WriteLine("InitializeChromium called Contact Support"); _webBrowser = BrowserManager.RequestChromiumWebBrowser("https://trade-ideas.com/"); _webBrowser.Dock = DockStyle.Fill; _webBrowser.IsBrowserInitializedChanged += _webBrowser_IsBrowserInitializedChanged; _webBrowser.JavascriptObjectRepository.Settings.LegacyBindingEnabled = true; // Set to allow Javascript bridging. _webBrowser.JavascriptObjectRepository.Register("contactSupportObj", _contactSupportJsInterops, true, BindingOptions.DefaultBinder); // Javascript class. /* Execute a script right after the html template load * 1. Initializes the beacon * 2. Add event listeners to these beacon's actions: close, ready * Close for closing the Contact Support Window after the beacon's closure * Ready for applying css customizations to the beacon for UI adjustments * 3. Open the beacon automatically */ _webBrowser.ExecuteScriptAsyncWhenPageLoaded("!function(e,t,n){function a(){var e=t.getElementsByTagName(\"script\")[0],n=t.createElement(\"script\");n.type=\"text/javascript\",n.async=!0,n.src=\"https://beacon-v2.helpscout.net\",e.parentNode.insertBefore(n,e)}if(e.Beacon=n=function(t,n,a){e.Beacon.readyQueue.push({method:t,options:n,data:a})},n.readyQueue=[],\"complete\"===t.readyState)return a();e.attachEvent?e.attachEvent(\"onload\",a):e.addEventListener(\"load\",a,!1)}(window,document,window.Beacon||function(){});\r\n Beacon('init', '008b82bf-3f85-4ec6-ab4b-21b71ed257aa');Beacon('on', 'close', () => contactSupportObj.closeBeacon());Beacon('on', 'ready', () => {document.querySelector('.hsds-beacon .bQymmx.is-mobile').style.inset = '0px 0px 0px'; document.querySelector('.hsds-beacon .bQymmx.is-mobile').style.height = '100%';});Beacon('open');\r\n"); //Subscribe to the beacon's closing event in order to replicate that action over this parent window _contactSupportJsInterops.OnBeaconClosed += OnBeaconClosed; } catch (Exception e) { string debugView = e.ToString(); TILogger.Error(e.Message, e); } } /// /// Set the chromium browser to load the beacon in mobile mode. /// This ensures a better responsive experience that fully adapts to the Contact Support /// window host. /// private void _webBrowser_IsBrowserInitializedChanged(object sender, EventArgs e) { if (_webBrowser.IsBrowserInitialized) { var client = _webBrowser.GetDevToolsClient(); client.Emulation.SetUserAgentOverrideAsync("Mozilla/5.0 (Linux; Android 10; SM-G975F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Mobile Safari/537.36"); } } /// /// Load the html template for the Contact Support Beacon /// private void LoadContactSupportTemplate() { if (null != _webBrowser && !_webBrowser.IsDisposed) { string curDir = new Uri(Directory.GetCurrentDirectory()).ToString(); _webBrowser.Load($"{curDir}/Resources/ContactSupportPage.html"); } } /// /// Dispose the resources used by the Chromium Webbrowser before /// closing the Contact Support window. /// private void ContactSupport_FormClosing(object sender, FormClosingEventArgs e) { if (null != _webBrowser && _webBrowser.IsBrowserInitialized && !_webBrowser.IsDisposed) { // Catch exception: Browser is not yet initialized. try { Hide(); _webBrowser.Stop(); SuspendLayout(); _webBrowser.IsBrowserInitializedChanged -= _webBrowser_IsBrowserInitializedChanged; _contactSupportJsInterops.OnBeaconClosed -= OnBeaconClosed; if (Controls.Contains(_webBrowser)) Controls.Remove(_webBrowser); ResumeLayout(false); BrowserManager.RequestBrowserDisposal(_webBrowser); } catch (Exception ex) { string debugView = ex.ToString(); TILogger.Error(ex.Message, ex); } } } /// /// Close the Contact Support window when the beacon is closed /// private void OnBeaconClosed() { this.BeginInvokeIfRequired(delegate { Close(); }); } /* In order to declare this form as an unpinned window, * the ISaveLayout has to be inherited and the presence * of the SaveLayout method is mandatory */ public void SaveLayout(XmlNode parent) { throw new NotImplementedException(); } public delegate void ChartJavaScriptBridgeOnBeaconClosedHandler(); public delegate void ChartJavaScriptBridgeOnBeaconReadyHandler(); /// /// This class handles the calls from the html template and the beacon /// to the Contact Support windows form. /// public class ContactSupportJsInterops { public event ChartJavaScriptBridgeOnBeaconClosedHandler OnBeaconClosed; public void closeBeacon() { OnBeaconClosed?.Invoke(); } } } }