using Bridge.Html5; using System; using System.Collections.Generic; namespace FrontendRouting { public static class FeRoutingManager { public static event EventHandler Navigated; private static readonly Dictionary Routes = new Dictionary(); private static FeRoutingView _currentView; private static string _basePath; private static FeRoutingView _pageNoFoundView = new DefaultPageNoFoundView(); private static Node _parentNode = Window.Document.Body; public static FeRoutingView PageNoFoundView { get => _pageNoFoundView; set => _pageNoFoundView = value ?? throw new ArgumentNullException(nameof(value)); } public static Node ParentNode { get => _parentNode; set { _currentView?.Leave(); _parentNode = value ?? throw new ArgumentNullException(nameof(value)); _currentView?.Enter(_parentNode); } } public static void Register(string path, FeRoutingView view) { if (false == path.StartsWith("/")) throw new ArgumentException($"{nameof(path)} must starts with /", nameof(path)); if (Routes.ContainsKey(path)) throw new ArgumentException($"Route path `{path}' already registed", nameof(path)); Routes.Add(path, view); } public static void UnRegister(string path) { Routes.Remove(path); } public static void Run(string basePath = "/") { if (null != _basePath) throw new InvalidOperationException("Already running"); if (false == basePath.StartsWith("/")) throw new ArgumentException($"{nameof(basePath)} must starts with /", nameof(basePath)); _basePath = basePath; Go(null); Window.AddEventListener(EventType.PopState, Window_PopState); } private static void Window_PopState(Event arg) { if (Go(null)) return; arg.PreventDefault(); Window.History.Go(1); } public static bool Go(string path, bool replace = false) { if (null != _currentView) return _currentView.BeforeLeave(() => GoInternal(path, replace)); return GoInternal(path, replace); } private static bool GoInternal(string path, bool replace) { if (null != path) { if (replace) Window.History.ReplaceState(null, null, path); else Window.History.PushState(null, null, path); } var routeKey = Window.Location.PathName; if (routeKey.StartsWith(_basePath)) routeKey = routeKey.Substring(_basePath.Length - 1); var targetView = Routes.TryGetValue(routeKey, out var controller) ? controller : PageNoFoundView; if (targetView.BeforeEnter(_currentView)) { _currentView?.Leave(); _currentView = targetView; _currentView.Enter(_parentNode); OnNavigated(); return true; } return false; } private static void OnNavigated() { Navigated?.Invoke(null, EventArgs.Empty); } } }