diff --git a/Wino.BackgroundTasks/Wino.BackgroundTasks.NET8.csproj b/Wino.BackgroundTasks/Wino.BackgroundTasks.NET8.csproj index 9b2a5323..ae774d76 100644 --- a/Wino.BackgroundTasks/Wino.BackgroundTasks.NET8.csproj +++ b/Wino.BackgroundTasks/Wino.BackgroundTasks.NET8.csproj @@ -1,8 +1,9 @@  net8.0-windows10.0.22621.0 - 10.0.17763.0 + 10.0.19041.0 Wino.BackgroundTasks.NET8 + win-x86;win-x64;win-arm64 win10-x86;win10-x64;win10-arm64 true diff --git a/Wino.Core.Domain/Wino.Core.Domain.NET8.csproj b/Wino.Core.Domain/Wino.Core.Domain.NET8.csproj index 7dc4c8e4..66ebaf5b 100644 --- a/Wino.Core.Domain/Wino.Core.Domain.NET8.csproj +++ b/Wino.Core.Domain/Wino.Core.Domain.NET8.csproj @@ -56,7 +56,6 @@ - diff --git a/Wino.Core.UWP/Dispatcher.cs b/Wino.Core.UWP/UWPDispatcher.cs similarity index 100% rename from Wino.Core.UWP/Dispatcher.cs rename to Wino.Core.UWP/UWPDispatcher.cs diff --git a/Wino.Core.UWP/WinAppDispatcher.cs b/Wino.Core.UWP/WinAppDispatcher.cs new file mode 100644 index 00000000..9966606d --- /dev/null +++ b/Wino.Core.UWP/WinAppDispatcher.cs @@ -0,0 +1,20 @@ +using System; +using System.Threading.Tasks; +using CommunityToolkit.WinUI; +using Microsoft.UI.Dispatching; +using Wino.Core.Domain.Interfaces; + +namespace Wino.Core.WinUI +{ + public class WinAppDispatcher : IDispatcher + { + private readonly DispatcherQueue _dispatcherQueue; + + public WinAppDispatcher(DispatcherQueue dispatcherQueue) + { + _dispatcherQueue = dispatcherQueue; + } + + public Task ExecuteOnUIThread(Action action) => _dispatcherQueue.EnqueueAsync(() => { action(); }); + } +} diff --git a/Wino.Core.UWP/Wino.Core.WinUI.csproj b/Wino.Core.UWP/Wino.Core.WinUI.csproj index f0017a82..bb2046be 100644 --- a/Wino.Core.UWP/Wino.Core.WinUI.csproj +++ b/Wino.Core.UWP/Wino.Core.WinUI.csproj @@ -1,12 +1,13 @@  net8.0-windows10.0.22621.0 - 10.0.17763.0 + 10.0.19041.0 Wino.Core.WinUI win-x86;win-x64;win-arm64 win10-x86;win10-x64;win10-arm64 true + diff --git a/Wino.Mail.WinUI/Activation/ActivationHandler.cs b/Wino.Mail.WinUI/Activation/ActivationHandler.cs new file mode 100644 index 00000000..5beef227 --- /dev/null +++ b/Wino.Mail.WinUI/Activation/ActivationHandler.cs @@ -0,0 +1,39 @@ +using System.Threading.Tasks; + +namespace Wino.Activation +{ + // For more information on understanding and extending activation flow see + // https://github.com/microsoft/TemplateStudio/blob/main/docs/UWP/activation.md + internal abstract class ActivationHandler + { + public abstract bool CanHandle(object args); + + public abstract Task HandleAsync(object args); + } + + // Extend this class to implement new ActivationHandlers + internal abstract class ActivationHandler : ActivationHandler + where T : class + { + // Override this method to add the activation logic in your activation handler + protected abstract Task HandleInternalAsync(T args); + + public override async Task HandleAsync(object args) + { + await HandleInternalAsync(args as T); + } + + public override bool CanHandle(object args) + { + // CanHandle checks the args is of type you have configured + return args is T && CanHandleInternal(args as T); + } + + // You can override this method to add extra validation on activation args + // to determine if your ActivationHandler should handle this activation args + protected virtual bool CanHandleInternal(T args) + { + return true; + } + } +} diff --git a/Wino.Mail.WinUI/Activation/BackgroundActivationHandler.cs b/Wino.Mail.WinUI/Activation/BackgroundActivationHandler.cs new file mode 100644 index 00000000..2e82ce4e --- /dev/null +++ b/Wino.Mail.WinUI/Activation/BackgroundActivationHandler.cs @@ -0,0 +1,154 @@ +using System.Threading.Tasks; + +using Serilog; +using Windows.ApplicationModel.Activation; +using Windows.ApplicationModel.Background; +using Windows.UI.Notifications; +using Wino.Core.Domain; +using Wino.Core.Domain.Enums; +using Wino.Core.Domain.Interfaces; +using Wino.Core.Domain.Models.MailItem; +using Wino.Core.UWP.Services; + +#if NET8_0 +using CommunityToolkit.WinUI.Notifications; +#else +using Microsoft.Toolkit.Uwp.Notifications; +#endif + +namespace Wino.Activation +{ + internal class BackgroundActivationHandler : ActivationHandler + { + private const string BackgroundExecutionLogTag = "[BackgroundExecution] "; + + private readonly IWinoRequestDelegator _winoRequestDelegator; + private readonly INativeAppService _nativeAppService; + private readonly IWinoRequestProcessor _winoRequestProcessor; + private readonly IWinoServerConnectionManager _winoServerConnectionManager; + private readonly IMailService _mailService; + private ToastArguments _toastArguments; + + BackgroundTaskDeferral _deferral; + public BackgroundActivationHandler(IWinoRequestDelegator winoRequestDelegator, + INativeAppService nativeAppService, + IWinoRequestProcessor winoRequestProcessor, + IWinoServerConnectionManager winoServerConnectionManager, + IMailService mailService) + { + _winoRequestDelegator = winoRequestDelegator; + _nativeAppService = nativeAppService; + _winoRequestProcessor = winoRequestProcessor; + _winoServerConnectionManager = winoServerConnectionManager; + _mailService = mailService; + } + + protected override async Task HandleInternalAsync(BackgroundActivatedEventArgs args) + { + var instance = args.TaskInstance; + var taskName = instance.Task.Name; + + instance.Canceled -= OnBackgroundExecutionCanceled; + instance.Canceled += OnBackgroundExecutionCanceled; + + _deferral = instance.GetDeferral(); + + if (taskName == BackgroundTaskService.ToastActivationTaskEx) + { + if (instance.TriggerDetails is ToastNotificationActionTriggerDetail toastNotificationActionTriggerDetail) + _toastArguments = ToastArguments.Parse(toastNotificationActionTriggerDetail.Argument); + + // All toast activation mail actions are handled here like mark as read or delete. + // This should not launch the application on the foreground. + + // Get the action and mail item id. + // Prepare package and send to delegator. + + if (_toastArguments.TryGetValue(Constants.ToastMailItemIdKey, out string mailItemId) && + _toastArguments.TryGetValue(Constants.ToastActionKey, out MailOperation action) && + _toastArguments.TryGetValue(Constants.ToastMailItemRemoteFolderIdKey, out string remoteFolderId)) + { + var mailItem = await _mailService.GetSingleMailItemAsync(mailItemId, remoteFolderId); + + if (mailItem == null) return; + + if (_nativeAppService.IsAppRunning()) + { + // Just send the package. We should reflect the UI changes as well. + var package = new MailOperationPreperationRequest(action, mailItem); + + await _winoRequestDelegator.ExecuteAsync(package); + } + else + { + // We need to synchronize changes without reflection the UI changes. + + // var synchronizer = _winoSynchronizerFactory.GetAccountSynchronizer(mailItem.AssignedAccount.Id); + var prepRequest = new MailOperationPreperationRequest(action, mailItem); + + var requests = await _winoRequestProcessor.PrepareRequestsAsync(prepRequest); + + foreach (var request in requests) + { + _winoServerConnectionManager.QueueRequest(request, mailItem.AssignedAccount.Id); + + // synchronizer.QueueRequest(request); + } + + //var options = new SynchronizationOptions() + //{ + // Type = SynchronizationType.ExecuteRequests, + // AccountId = mailItem.AssignedAccount.Id + //}; + + //await synchronizer.SynchronizeAsync(options); + } + } + } + + instance.Canceled -= OnBackgroundExecutionCanceled; + + _deferral.Complete(); + } + + private void OnBackgroundExecutionCanceled(Windows.ApplicationModel.Background.IBackgroundTaskInstance sender, Windows.ApplicationModel.Background.BackgroundTaskCancellationReason reason) + { + Log.Error($"{BackgroundExecutionLogTag} ({sender.Task.Name}) Background task is canceled. Reason -> {reason}"); + + _deferral?.Complete(); + } + + protected override bool CanHandleInternal(BackgroundActivatedEventArgs args) + { + var instance = args.TaskInstance; + var taskName = instance.Task.Name; + + if (taskName == BackgroundTaskService.ToastActivationTaskEx) + { + // User clicked Mark as Read or Delete in toast notification. + // MailId and Action must present in the arguments. + + return true; + + //if (instance.TriggerDetails is ToastNotificationActionTriggerDetail toastNotificationActionTriggerDetail) + //{ + // _toastArguments = ToastArguments.Parse(toastNotificationActionTriggerDetail.Argument); + + // return + // _toastArguments.Contains(Constants.ToastMailItemIdKey) && + // _toastArguments.Contains(Constants.ToastActionKey); + //} + + } + else if (taskName == BackgroundTaskService.BackgroundSynchronizationTimerTaskNameEx) + { + // This is timer based background synchronization. + + + return true; + } + + return false; + } + } +} diff --git a/Wino.Mail.WinUI/Activation/DefaultActivationHandler.cs b/Wino.Mail.WinUI/Activation/DefaultActivationHandler.cs new file mode 100644 index 00000000..acb80397 --- /dev/null +++ b/Wino.Mail.WinUI/Activation/DefaultActivationHandler.cs @@ -0,0 +1,30 @@ +using System.Threading.Tasks; +using Windows.ApplicationModel.Activation; +using Wino.Views; + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Media.Animation; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Media.Animation; +#endif + +namespace Wino.Activation +{ + internal class DefaultActivationHandler : ActivationHandler + { + protected override Task HandleInternalAsync(IActivatedEventArgs args) + { + (Window.Current.Content as Frame).Navigate(typeof(AppShell), null, new DrillInNavigationTransitionInfo()); + + return Task.CompletedTask; + } + + // Only navigate if Frame content doesn't exist. + protected override bool CanHandleInternal(IActivatedEventArgs args) + => (Window.Current?.Content as Frame)?.Content == null; + } +} diff --git a/Wino.Mail.WinUI/Activation/FileActivationHandler.cs b/Wino.Mail.WinUI/Activation/FileActivationHandler.cs new file mode 100644 index 00000000..4ea5a5b1 --- /dev/null +++ b/Wino.Mail.WinUI/Activation/FileActivationHandler.cs @@ -0,0 +1,76 @@ +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Windows.ApplicationModel.Activation; +using Windows.Storage; +using Wino.Core.Domain.Interfaces; +using Wino.Core.Services; +using Wino.Helpers; +using Wino.Views; + +#if NET8_0 +using Microsoft.UI.Xaml.Media.Animation; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Media.Animation; +#endif + +namespace Wino.Activation +{ + internal class FileActivationHandler : ActivationHandler + { + private readonly INativeAppService _nativeAppService; + private readonly IMimeFileService _mimeFileService; + private readonly IStatePersistanceService _statePersistanceService; + private readonly IWinoNavigationService _winoNavigationService; + + public FileActivationHandler(INativeAppService nativeAppService, + IMimeFileService mimeFileService, + IStatePersistanceService statePersistanceService, + IWinoNavigationService winoNavigationService) + { + _nativeAppService = nativeAppService; + _mimeFileService = mimeFileService; + _statePersistanceService = statePersistanceService; + _winoNavigationService = winoNavigationService; + } + + protected override async Task HandleInternalAsync(FileActivatedEventArgs args) + { + // Always handle the last item passed. + // Multiple files are not supported. + + var file = args.Files.Last() as StorageFile; + + // Only EML files are supported now. + var fileExtension = Path.GetExtension(file.Path); + + if (string.Equals(fileExtension, ".eml", StringComparison.OrdinalIgnoreCase)) + { + var fileBytes = await file.ReadBytesAsync(); + var directoryName = Path.GetDirectoryName(file.Path); + + var messageInformation = await _mimeFileService.GetMimeMessageInformationAsync(fileBytes, directoryName).ConfigureAwait(false); + + if (_nativeAppService.IsAppRunning()) + { + // TODO: Activate another Window and go to mail rendering page. + _winoNavigationService.NavigateRendering(messageInformation); + } + else + { + _statePersistanceService.ShouldShiftMailRenderingDesign = true; + + (Window.Current.Content as Frame).Navigate(typeof(MailRenderingPage), messageInformation, new DrillInNavigationTransitionInfo()); + } + } + } + + protected override bool CanHandleInternal(FileActivatedEventArgs args) => args.Files.Any(); + + } +} diff --git a/Wino.Mail.WinUI/Activation/ProtocolActivationHandler.cs b/Wino.Mail.WinUI/Activation/ProtocolActivationHandler.cs new file mode 100644 index 00000000..f6ad3aa9 --- /dev/null +++ b/Wino.Mail.WinUI/Activation/ProtocolActivationHandler.cs @@ -0,0 +1,56 @@ +using System.Threading.Tasks; +using System.Web; +using CommunityToolkit.Mvvm.Messaging; +using Windows.ApplicationModel.Activation; +using Wino.Core.Domain.Interfaces; +using Wino.Core.Messages.Authorization; +using Wino.Core.Messages.Shell; + +namespace Wino.Activation +{ + internal class ProtocolActivationHandler : ActivationHandler + { + private const string GoogleAuthorizationProtocolTag = "google.pw.oauth2"; + private const string MailtoProtocolTag = "mailto:"; + + private readonly INativeAppService _nativeAppService; + private readonly ILaunchProtocolService _launchProtocolService; + + public ProtocolActivationHandler(INativeAppService nativeAppService, ILaunchProtocolService launchProtocolService) + { + _nativeAppService = nativeAppService; + _launchProtocolService = launchProtocolService; + } + + protected override Task HandleInternalAsync(ProtocolActivatedEventArgs args) + { + // Check URI prefix. + + var protocolString = args.Uri.AbsoluteUri; + + // Google OAuth Response + if (protocolString.StartsWith(GoogleAuthorizationProtocolTag)) + { + // App must be working already. No need to check for running state. + WeakReferenceMessenger.Default.Send(new ProtocolAuthorizationCallbackReceived(args.Uri)); + } + else if (protocolString.StartsWith(MailtoProtocolTag)) + { + // mailto activation. Try to parse params. + + var replaced = protocolString.Replace(MailtoProtocolTag, "mailto="); + replaced = Wino.Core.Extensions.StringExtensions.ReplaceFirst(replaced, "?", "&"); + + _launchProtocolService.MailtoParameters = HttpUtility.ParseQueryString(replaced); + + if (_nativeAppService.IsAppRunning()) + { + // Just send publish a message. Shell will continue. + WeakReferenceMessenger.Default.Send(new MailtoProtocolMessageRequested()); + } + } + + return Task.CompletedTask; + } + } +} diff --git a/Wino.Mail.WinUI/Activation/ToastNotificationActivationHandler.cs b/Wino.Mail.WinUI/Activation/ToastNotificationActivationHandler.cs new file mode 100644 index 00000000..15b68c6d --- /dev/null +++ b/Wino.Mail.WinUI/Activation/ToastNotificationActivationHandler.cs @@ -0,0 +1,86 @@ +using System; +using System.Threading.Tasks; +using CommunityToolkit.Mvvm.Messaging; +using Microsoft.Extensions.DependencyInjection; +using Serilog; +using Windows.ApplicationModel.Activation; +using Wino.Core.Domain; +using Wino.Core.Domain.Interfaces; +using Wino.Core.Messages.Accounts; +using Wino.Mail.WinUI; + + +#if NET8_0 +using CommunityToolkit.WinUI.Notifications; +#else +using Microsoft.Toolkit.Uwp.Notifications; +#endif + +namespace Wino.Activation +{ + /// + /// This handler will only handle the toasts that runs on foreground. + /// Background executions are not handled here like mark as read or delete. + /// + internal class ToastNotificationActivationHandler : ActivationHandler + { + private readonly INativeAppService _nativeAppService; + private readonly IMailService _mailService; + private readonly IFolderService _folderService; + + private ToastArguments _toastArguments; + + public ToastNotificationActivationHandler(INativeAppService nativeAppService, + IMailService mailService, + IFolderService folderService) + { + _nativeAppService = nativeAppService; + _mailService = mailService; + _folderService = folderService; + } + + protected override async Task HandleInternalAsync(ToastNotificationActivatedEventArgs args) + { + // Create the mail item navigation event. + // If the app is running, it'll be picked up by the Messenger. + // Otherwise we'll save it and handle it when the shell loads all accounts. + + // Parse the mail unique id and perform above actions. + if (Guid.TryParse(_toastArguments[Constants.ToastMailItemIdKey], out Guid mailItemUniqueId)) + { + var account = await _mailService.GetMailAccountByUniqueIdAsync(mailItemUniqueId).ConfigureAwait(false); + if (account == null) return; + + var mailItem = await _mailService.GetSingleMailItemAsync(mailItemUniqueId).ConfigureAwait(false); + if (mailItem == null) return; + + var message = new AccountMenuItemExtended(mailItem.AssignedFolder.Id, mailItem); + + // Delegate this event to LaunchProtocolService so app shell can pick it up on launch if app doesn't work. + var launchProtocolService = App.Current.Services.GetService(); + launchProtocolService.LaunchParameter = message; + + // Send the messsage anyways. Launch protocol service will be ignored if the message is picked up by subscriber shell. + WeakReferenceMessenger.Default.Send(message); + } + } + + protected override bool CanHandleInternal(ToastNotificationActivatedEventArgs args) + { + try + { + _toastArguments = ToastArguments.Parse(args.Argument); + + return + _toastArguments.Contains(Constants.ToastMailItemIdKey) && + _toastArguments.Contains(Constants.ToastActionKey); + } + catch (Exception ex) + { + Log.Error(ex, "Couldn't handle parsing toast notification arguments for foreground navigate."); + } + + return false; + } + } +} diff --git a/Wino.Mail.WinUI/App.xaml b/Wino.Mail.WinUI/App.xaml index 91ce2c63..f0538f18 100644 --- a/Wino.Mail.WinUI/App.xaml +++ b/Wino.Mail.WinUI/App.xaml @@ -1,4 +1,4 @@ - + - + - + diff --git a/Wino.Mail.WinUI/App.xaml.cs b/Wino.Mail.WinUI/App.xaml.cs index 00a3ebf8..bb36f1d4 100644 --- a/Wino.Mail.WinUI/App.xaml.cs +++ b/Wino.Mail.WinUI/App.xaml.cs @@ -1,50 +1,79 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices.WindowsRuntime; +using System.Text; +using Microsoft.Extensions.DependencyInjection; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; -using Microsoft.UI.Xaml.Controls.Primitives; -using Microsoft.UI.Xaml.Data; -using Microsoft.UI.Xaml.Input; using Microsoft.UI.Xaml.Media; -using Microsoft.UI.Xaml.Navigation; -using Microsoft.UI.Xaml.Shapes; -using Windows.ApplicationModel; -using Windows.ApplicationModel.Activation; -using Windows.Foundation; -using Windows.Foundation.Collections; - -// To learn more about WinUI, the WinUI project structure, -// and more about our project templates, see: http://aka.ms/winui-project-info. +using Windows.Storage; +using Wino.Core.Domain.Interfaces; +using Wino.Core.Services; +using Wino.Core.WinUI.Services; +using Wino.Views; +using WinUIEx; namespace Wino.Mail.WinUI { - /// - /// Provides application-specific behavior to supplement the default Application class. - /// public partial class App : Application { - /// - /// Initializes the singleton application object. This is the first line of authored code - /// executed, and as such is the logical equivalent of main() or WinMain(). - /// + private WindowEx m_Window; + private Frame m_ShellFrame; + + private readonly IApplicationConfiguration _applicationFolderConfiguration; + public App() { - this.InitializeComponent(); + if (WebAuthenticator.CheckOAuthRedirectionActivation()) return; + + InitializeComponent(); + + Services = ConfigureServices(); + + _applicationFolderConfiguration = Services.GetService(); + _logInitializer = Services.GetService(); + + ConfigureLogger(); + ConfigureAppCenter(); + ConfigurePrelaunch(); + ConfigureXbox(); + + // Make sure the paths are setup on app start. + _applicationFolderConfiguration.ApplicationDataFolderPath = ApplicationData.Current.LocalFolder.Path; + _applicationFolderConfiguration.PublisherSharedFolderPath = ApplicationData.Current.GetPublisherCacheFolder(ApplicationConfiguration.SharedFolderName).Path; + + _themeService = Services.GetService(); + _databaseService = Services.GetService(); + _translationService = Services.GetService(); + _appShellService = Services.GetService(); + + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); } - /// - /// Invoked when the application is launched. - /// - /// Details about the launch request and process. - protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args) + protected override async void OnLaunched(LaunchActivatedEventArgs args) { - m_window = new MainWindow(); - m_window.Activate(); + ConfigureWindow(); + + _appShellService.AppWindow = m_Window; + + foreach (var service in initializeServices) + { + await service.InitializeAsync(); + } + + m_ShellFrame.Navigate(typeof(AppShell)); + m_Window.Activate(); } - private Window m_window; + private void ConfigureWindow() + { + m_Window = new WindowEx + { + SystemBackdrop = new MicaBackdrop(), + ExtendsContentIntoTitleBar = true, + MinWidth = 420 + }; + + m_ShellFrame = new Frame(); + + m_Window.Content = m_ShellFrame; + } } } diff --git a/Wino.Mail.WinUI/AppShell.xaml b/Wino.Mail.WinUI/AppShell.xaml new file mode 100644 index 00000000..f8f886f2 --- /dev/null +++ b/Wino.Mail.WinUI/AppShell.xaml @@ -0,0 +1,534 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wino.Mail.WinUI/AppShell.xaml.cs b/Wino.Mail.WinUI/AppShell.xaml.cs new file mode 100644 index 00000000..1638bd25 --- /dev/null +++ b/Wino.Mail.WinUI/AppShell.xaml.cs @@ -0,0 +1,302 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using CommunityToolkit.Mvvm.Input; +using CommunityToolkit.Mvvm.Messaging; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Controls.Primitives; +using Microsoft.UI.Xaml.Input; +using Windows.ApplicationModel.Core; +using Windows.Foundation; +using Wino.Controls; +using Wino.Core.Domain; +using Wino.Core.Domain.Entities; +using Wino.Core.Domain.Interfaces; +using Wino.Core.Domain.Models.Folders; +using Wino.Core.Domain.Models.MailItem; +using Wino.Core.Domain.Models.Navigation; +using Wino.Core.Messages.Accounts; +using Wino.Core.Messages.Mails; +using Wino.Core.Messages.Shell; +using Wino.Extensions; +using Wino.Mail.ViewModels.Data; +using Wino.MenuFlyouts; +using Wino.MenuFlyouts.Context; +using Wino.Views.Abstract; + +namespace Wino.Views +{ + public sealed partial class AppShell : AppShellAbstract, + IRecipient, + IRecipient, + IRecipient, + IRecipient + { + public AppShell() : base() + { + InitializeComponent(); + + var coreTitleBar = CoreApplication.GetCurrentView().TitleBar; + coreTitleBar.LayoutMetricsChanged += TitleBarLayoutUpdated; + } + + private void TitleBarLayoutUpdated(CoreApplicationViewTitleBar sender, object args) => UpdateTitleBarLayout(sender); + + private void UpdateTitleBarLayout(CoreApplicationViewTitleBar coreTitleBar) => RealAppBar.SystemReserved = coreTitleBar.SystemOverlayRightInset; + + private async void ItemDroppedOnFolder(object sender, DragEventArgs e) + { + // Validate package content. + if (sender is WinoNavigationViewItem droppedContainer) + { + droppedContainer.IsDraggingItemOver = false; + + if (CanContinueDragDrop(droppedContainer, e)) + { + if (droppedContainer.DataContext is IBaseFolderMenuItem draggingFolder) + { + var mailCopies = new List(); + + var dragPackage = e.DataView.Properties[nameof(MailDragPackage)] as MailDragPackage; + e.AcceptedOperation = Windows.ApplicationModel.DataTransfer.DataPackageOperation.Move; + + // Extract mail copies from IMailItem. + // ThreadViewModels will be divided into pieces. + + foreach (var item in dragPackage.DraggingMails) + { + if (item is MailItemViewModel singleMailItemViewModel) + { + mailCopies.Add(singleMailItemViewModel.MailCopy); + } + else if (item is ThreadMailItemViewModel threadViewModel) + { + mailCopies.AddRange(threadViewModel.GetMailCopies()); + } + } + + await ViewModel.PerformMoveOperationAsync(mailCopies, draggingFolder); + } + } + } + } + + private void ItemDragLeaveFromFolder(object sender, DragEventArgs e) + { + if (sender is WinoNavigationViewItem leavingContainer) + { + leavingContainer.IsDraggingItemOver = false; + } + } + + private bool CanContinueDragDrop(WinoNavigationViewItem interactingContainer, DragEventArgs args) + { + // TODO: Maybe override caption with some information why the validation failed? + // Note: Caption has a max length. It may be trimmed in some languages. + + if (interactingContainer == null || !args.DataView.Properties.ContainsKey(nameof(MailDragPackage))) return false; + + var dragPackage = args.DataView.Properties[nameof(MailDragPackage)] as MailDragPackage; + + // Invalid package. + if (!dragPackage.DraggingMails.Any()) return false; + + // Check whether source and target folder are the same. + if (interactingContainer.IsSelected) return false; + + // Check if the interacting container is a folder. + if (!(interactingContainer.DataContext is IBaseFolderMenuItem folderMenuItem)) return false; + + // Check if the folder is a move target. + if (!folderMenuItem.IsMoveTarget) return false; + + // Check whether the moving item's account has at least one same as the target folder's account. + var draggedAccountIds = folderMenuItem.HandlingFolders.Select(a => a.MailAccountId); + + if (!dragPackage.DraggingMails.Any(a => draggedAccountIds.Contains(a.AssignedAccount.Id))) return false; + + return true; + } + + private void ItemDragEnterOnFolder(object sender, DragEventArgs e) + { + // Validate package content. + if (sender is WinoNavigationViewItem droppedContainer && CanContinueDragDrop(droppedContainer, e)) + { + droppedContainer.IsDraggingItemOver = true; + + var draggingFolder = droppedContainer.DataContext as IBaseFolderMenuItem; + + e.AcceptedOperation = Windows.ApplicationModel.DataTransfer.DataPackageOperation.Move; + e.DragUIOverride.Caption = string.Format(Translator.DragMoveToFolderCaption, draggingFolder.FolderName); + } + } + + public async void Receive(AccountMenuItemExtended message) + { + await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, async () => + { + if (message.FolderId == default) return; + + if (ViewModel.MenuItems.TryGetFolderMenuItem(message.FolderId, out IBaseFolderMenuItem foundMenuItem)) + { + if (foundMenuItem == null) return; + + foundMenuItem.Expand(); + + await ViewModel.NavigateFolderAsync(foundMenuItem); + + navigationView.SelectedItem = foundMenuItem; + + if (message.NavigateMailItem == null) return; + + // At this point folder is navigated and items are loaded. + WeakReferenceMessenger.Default.Send(new MailItemNavigationRequested(message.NavigateMailItem.UniqueId)); + } + }); + } + + private async void MenuSelectionChanged(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewSelectionChangedEventArgs args) + { + if (args.SelectedItem is IMenuItem invokedMenuItem) + { + await ViewModel.MenuItemInvokedOrSelectedAsync(invokedMenuItem); + } + } + + private async void NavigationViewItemInvoked(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewItemInvokedEventArgs args) + { + // SelectsOnInvoked is handled in MenuSelectionChanged. + // This part is only for the items that are not selectable. + if (args.InvokedItemContainer is WinoNavigationViewItem winoNavigationViewItem) + { + if (winoNavigationViewItem.SelectsOnInvoked) return; + + await ViewModel.MenuItemInvokedOrSelectedAsync(winoNavigationViewItem.DataContext as IMenuItem); + } + } + + public void Receive(NavigateMailFolderEvent message) + { + if (message.BaseFolderMenuItem == null) return; + + if (navigationView.SelectedItem != message.BaseFolderMenuItem) + { + var navigateFolderArgs = new NavigateMailFolderEventArgs(message.BaseFolderMenuItem, message.FolderInitLoadAwaitTask); + + ViewModel.NavigationService.NavigateFolder(navigateFolderArgs); + + // Prevent double navigation. + navigationView.SelectionChanged -= MenuSelectionChanged; + navigationView.SelectedItem = message.BaseFolderMenuItem; + navigationView.SelectionChanged += MenuSelectionChanged; + } + else + { + // Complete the init task since we are already on the right page. + message.FolderInitLoadAwaitTask?.TrySetResult(true); + } + } + + private void ShellFrameContentNavigated(object sender, Microsoft.UI.Xaml.Navigation.NavigationEventArgs e) + => RealAppBar.ShellFrameContent = (e.Content as BasePage).ShellContent; + + private void BackButtonClicked(Controls.Advanced.WinoAppTitleBar sender, RoutedEventArgs args) + { + WeakReferenceMessenger.Default.Send(new ClearMailSelectionsRequested()); + WeakReferenceMessenger.Default.Send(new DisposeRenderingFrameRequested()); + WeakReferenceMessenger.Default.Send(new ShellStateUpdated()); + + } + + private async void MenuItemContextRequested(UIElement sender, ContextRequestedEventArgs args) + { + // Delegate this request to ViewModel. + // VM will prepare available actions for this folder and show Menu Flyout. + + if (sender is WinoNavigationViewItem menuItem && + menuItem.DataContext is IBaseFolderMenuItem baseFolderMenuItem && + baseFolderMenuItem.IsMoveTarget && + args.TryGetPosition(sender, out Point p)) + { + args.Handled = true; + + var source = new TaskCompletionSource(); + + var actions = ViewModel.GetFolderContextMenuActions(baseFolderMenuItem); + var flyout = new FolderOperationFlyout(actions, source); + + flyout.ShowAt(menuItem, new FlyoutShowOptions() + { + ShowMode = FlyoutShowMode.Standard, + Position = new Point(p.X + 30, p.Y - 20) + }); + + var operation = await source.Task; + + flyout.Dispose(); + + // No action selected. + if (operation == null) return; + + await ViewModel.PerformFolderOperationAsync(operation.Operation, baseFolderMenuItem); + } + } + + public void Receive(CreateNewMailWithMultipleAccountsRequested message) + { + // Find the NewMail menu item container. + + var container = navigationView.ContainerFromMenuItem(ViewModel.CreateMailMenuItem); + + var flyout = new AccountSelectorFlyout(message.AllAccounts, ViewModel.CreateNewMailForAsync); + + flyout.ShowAt(container, new FlyoutShowOptions() + { + ShowMode = FlyoutShowMode.Auto, + Placement = FlyoutPlacementMode.Right + }); + } + + private void NavigationPaneOpening(Microsoft.UI.Xaml.Controls.NavigationView sender, object args) + { + // It's annoying that NavigationView doesn't respect expansion state of the items in Minimal display mode. + // Expanded items are collaped, and users need to expand them again. + // Regardless of the reason, we will expand the selected item if it's a folder with parent account for visibility. + + if (sender.DisplayMode == Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Minimal && sender.SelectedItem is IFolderMenuItem selectedFolderMenuItem) + { + selectedFolderMenuItem.Expand(); + } + } + + /// + /// InfoBar message is requested. + /// + public async void Receive(InfoBarMessageRequested message) + { + await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => + { + if (string.IsNullOrEmpty(message.ActionButtonTitle) || message.Action == null) + { + ShellInfoBar.ActionButton = null; + } + else + { + ShellInfoBar.ActionButton = new Button() + { + Content = message.ActionButtonTitle, + Command = new RelayCommand(message.Action) + }; + } + + ShellInfoBar.Message = message.Message; + ShellInfoBar.Title = message.Title; + ShellInfoBar.Severity = message.Severity.AsMUXCInfoBarSeverity(); + ShellInfoBar.IsOpen = true; + }); + } + } +} diff --git a/Wino.Mail.WinUI/AppThemes/Acrylic.xaml b/Wino.Mail.WinUI/AppThemes/Acrylic.xaml new file mode 100644 index 00000000..ef5325f4 --- /dev/null +++ b/Wino.Mail.WinUI/AppThemes/Acrylic.xaml @@ -0,0 +1,25 @@ + + + Acrylic + False + + Transparent + + + + + + #ecf0f1 + + + + + #2C2C2C + + + + diff --git a/Wino.Mail.WinUI/AppThemes/Clouds.xaml b/Wino.Mail.WinUI/AppThemes/Clouds.xaml new file mode 100644 index 00000000..a9590c94 --- /dev/null +++ b/Wino.Mail.WinUI/AppThemes/Clouds.xaml @@ -0,0 +1,18 @@ + + + Clouds + ms-appx:///BackgroundImages/Clouds.jpg + False + + + Transparent + + + + #b2dffc + + + #b2dffc + + + diff --git a/Wino.Mail.WinUI/AppThemes/Custom.xaml b/Wino.Mail.WinUI/AppThemes/Custom.xaml new file mode 100644 index 00000000..97df0020 --- /dev/null +++ b/Wino.Mail.WinUI/AppThemes/Custom.xaml @@ -0,0 +1,47 @@ + + + Custom + ms-appdata:///local/CustomWallpaper.jpg + False + + + + + 0,0,0,0 + 0,1,0,0 + 0,0,0,0 + + + + + #ecf0f1 + + #D9FFFFFF + + + + + + + + + #1f1f1f + + #E61F1F1F + + + + + + + + + + + diff --git a/Wino.Mail.WinUI/AppThemes/Forest.xaml b/Wino.Mail.WinUI/AppThemes/Forest.xaml new file mode 100644 index 00000000..b2654834 --- /dev/null +++ b/Wino.Mail.WinUI/AppThemes/Forest.xaml @@ -0,0 +1,21 @@ + + + Forest + ms-appx:///BackgroundImages/Forest.jpg + False + + + Transparent + + + + #A800D608 + + + #59001C01 + + + diff --git a/Wino.Mail.WinUI/AppThemes/Garden.xaml b/Wino.Mail.WinUI/AppThemes/Garden.xaml new file mode 100644 index 00000000..43521d52 --- /dev/null +++ b/Wino.Mail.WinUI/AppThemes/Garden.xaml @@ -0,0 +1,18 @@ + + + Garden + ms-appx:///BackgroundImages/Garden.jpg + False + + + Transparent + + + + #dcfad8 + + + #dcfad8 + + + diff --git a/Wino.Mail.WinUI/AppThemes/Mica.xaml b/Wino.Mail.WinUI/AppThemes/Mica.xaml new file mode 100644 index 00000000..41bb8860 --- /dev/null +++ b/Wino.Mail.WinUI/AppThemes/Mica.xaml @@ -0,0 +1,19 @@ + + + Mica + True + + Transparent + Transparent + + + + + + #ecf0f1 + + + #1f1f1f + + + diff --git a/Wino.Mail.WinUI/AppThemes/Nighty.xaml b/Wino.Mail.WinUI/AppThemes/Nighty.xaml new file mode 100644 index 00000000..e9d5819e --- /dev/null +++ b/Wino.Mail.WinUI/AppThemes/Nighty.xaml @@ -0,0 +1,20 @@ + + + Nighty + ms-appx:///BackgroundImages/Nighty.jpg + False + + + Transparent + + + + + #fdcb6e + + + + #5413191F + + + diff --git a/Wino.Mail.WinUI/AppThemes/Snowflake.xaml b/Wino.Mail.WinUI/AppThemes/Snowflake.xaml new file mode 100644 index 00000000..15f773d0 --- /dev/null +++ b/Wino.Mail.WinUI/AppThemes/Snowflake.xaml @@ -0,0 +1,20 @@ + + + Snowflake + ms-appx:///BackgroundImages/Snowflake.jpg + False + + + Transparent + + + + + #b0c6dd + + + + #b0c6dd + + + diff --git a/Wino.Mail.WinUI/AppThemes/TestTheme.xaml b/Wino.Mail.WinUI/AppThemes/TestTheme.xaml new file mode 100644 index 00000000..903b065b --- /dev/null +++ b/Wino.Mail.WinUI/AppThemes/TestTheme.xaml @@ -0,0 +1,22 @@ + + + TestTheme.xaml + + + + + ms-appx:///BackgroundImages/bg6.jpg + #A3FFFFFF + #A3FFFFFF + #fdcb6e + + + + ms-appx:///BackgroundImages/bg6.jpg + + #A3000000 + #A3000000 + #A3262626 + + + diff --git a/Wino.Mail.WinUI/Assets/BadgeLogo.scale-100.png b/Wino.Mail.WinUI/Assets/BadgeLogo.scale-100.png new file mode 100644 index 00000000..1534c12e Binary files /dev/null and b/Wino.Mail.WinUI/Assets/BadgeLogo.scale-100.png differ diff --git a/Wino.Mail.WinUI/Assets/BadgeLogo.scale-125.png b/Wino.Mail.WinUI/Assets/BadgeLogo.scale-125.png new file mode 100644 index 00000000..534de075 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/BadgeLogo.scale-125.png differ diff --git a/Wino.Mail.WinUI/Assets/BadgeLogo.scale-150.png b/Wino.Mail.WinUI/Assets/BadgeLogo.scale-150.png new file mode 100644 index 00000000..0470789a Binary files /dev/null and b/Wino.Mail.WinUI/Assets/BadgeLogo.scale-150.png differ diff --git a/Wino.Mail.WinUI/Assets/BadgeLogo.scale-200.png b/Wino.Mail.WinUI/Assets/BadgeLogo.scale-200.png new file mode 100644 index 00000000..842c6f84 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/BadgeLogo.scale-200.png differ diff --git a/Wino.Mail.WinUI/Assets/BadgeLogo.scale-400.png b/Wino.Mail.WinUI/Assets/BadgeLogo.scale-400.png new file mode 100644 index 00000000..ab34364e Binary files /dev/null and b/Wino.Mail.WinUI/Assets/BadgeLogo.scale-400.png differ diff --git a/Wino.Mail.WinUI/Assets/EML/eml.png b/Wino.Mail.WinUI/Assets/EML/eml.png new file mode 100644 index 00000000..7aeeb98f Binary files /dev/null and b/Wino.Mail.WinUI/Assets/EML/eml.png differ diff --git a/Wino.Mail.WinUI/Assets/FileTypes/type_archive.png b/Wino.Mail.WinUI/Assets/FileTypes/type_archive.png new file mode 100644 index 00000000..b4227523 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/FileTypes/type_archive.png differ diff --git a/Wino.Mail.WinUI/Assets/FileTypes/type_audio.png b/Wino.Mail.WinUI/Assets/FileTypes/type_audio.png new file mode 100644 index 00000000..5489d5e9 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/FileTypes/type_audio.png differ diff --git a/Wino.Mail.WinUI/Assets/FileTypes/type_executable.png b/Wino.Mail.WinUI/Assets/FileTypes/type_executable.png new file mode 100644 index 00000000..e8fc6e6e Binary files /dev/null and b/Wino.Mail.WinUI/Assets/FileTypes/type_executable.png differ diff --git a/Wino.Mail.WinUI/Assets/FileTypes/type_html.png b/Wino.Mail.WinUI/Assets/FileTypes/type_html.png new file mode 100644 index 00000000..2bf4e140 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/FileTypes/type_html.png differ diff --git a/Wino.Mail.WinUI/Assets/FileTypes/type_image.png b/Wino.Mail.WinUI/Assets/FileTypes/type_image.png new file mode 100644 index 00000000..378b9559 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/FileTypes/type_image.png differ diff --git a/Wino.Mail.WinUI/Assets/FileTypes/type_none.png b/Wino.Mail.WinUI/Assets/FileTypes/type_none.png new file mode 100644 index 00000000..900b00cc Binary files /dev/null and b/Wino.Mail.WinUI/Assets/FileTypes/type_none.png differ diff --git a/Wino.Mail.WinUI/Assets/FileTypes/type_other.png b/Wino.Mail.WinUI/Assets/FileTypes/type_other.png new file mode 100644 index 00000000..c16c9edd Binary files /dev/null and b/Wino.Mail.WinUI/Assets/FileTypes/type_other.png differ diff --git a/Wino.Mail.WinUI/Assets/FileTypes/type_pdf.png b/Wino.Mail.WinUI/Assets/FileTypes/type_pdf.png new file mode 100644 index 00000000..b08ee4a2 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/FileTypes/type_pdf.png differ diff --git a/Wino.Mail.WinUI/Assets/FileTypes/type_rar.png b/Wino.Mail.WinUI/Assets/FileTypes/type_rar.png new file mode 100644 index 00000000..4260115a Binary files /dev/null and b/Wino.Mail.WinUI/Assets/FileTypes/type_rar.png differ diff --git a/Wino.Mail.WinUI/Assets/FileTypes/type_video.png b/Wino.Mail.WinUI/Assets/FileTypes/type_video.png new file mode 100644 index 00000000..829bd686 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/FileTypes/type_video.png differ diff --git a/Wino.Mail.WinUI/Assets/LargeTile.scale-100.png b/Wino.Mail.WinUI/Assets/LargeTile.scale-100.png new file mode 100644 index 00000000..aca6e4e2 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/LargeTile.scale-100.png differ diff --git a/Wino.Mail.WinUI/Assets/LargeTile.scale-125.png b/Wino.Mail.WinUI/Assets/LargeTile.scale-125.png new file mode 100644 index 00000000..b80bf9d4 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/LargeTile.scale-125.png differ diff --git a/Wino.Mail.WinUI/Assets/LargeTile.scale-150.png b/Wino.Mail.WinUI/Assets/LargeTile.scale-150.png new file mode 100644 index 00000000..1ed2a001 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/LargeTile.scale-150.png differ diff --git a/Wino.Mail.WinUI/Assets/LargeTile.scale-200.png b/Wino.Mail.WinUI/Assets/LargeTile.scale-200.png new file mode 100644 index 00000000..a8e471dd Binary files /dev/null and b/Wino.Mail.WinUI/Assets/LargeTile.scale-200.png differ diff --git a/Wino.Mail.WinUI/Assets/LargeTile.scale-400.png b/Wino.Mail.WinUI/Assets/LargeTile.scale-400.png new file mode 100644 index 00000000..54cea310 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/LargeTile.scale-400.png differ diff --git a/Wino.Mail.WinUI/Assets/NotificationIcons/delete.png b/Wino.Mail.WinUI/Assets/NotificationIcons/delete.png new file mode 100644 index 00000000..bc46276e Binary files /dev/null and b/Wino.Mail.WinUI/Assets/NotificationIcons/delete.png differ diff --git a/Wino.Mail.WinUI/Assets/NotificationIcons/dismiss.png b/Wino.Mail.WinUI/Assets/NotificationIcons/dismiss.png new file mode 100644 index 00000000..63086036 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/NotificationIcons/dismiss.png differ diff --git a/Wino.Mail.WinUI/Assets/NotificationIcons/markread.png b/Wino.Mail.WinUI/Assets/NotificationIcons/markread.png new file mode 100644 index 00000000..114ab059 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/NotificationIcons/markread.png differ diff --git a/Wino.Mail.WinUI/Assets/NotificationIcons/profile-dark.png b/Wino.Mail.WinUI/Assets/NotificationIcons/profile-dark.png new file mode 100644 index 00000000..114b3af6 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/NotificationIcons/profile-dark.png differ diff --git a/Wino.Mail.WinUI/Assets/NotificationIcons/profile-light.png b/Wino.Mail.WinUI/Assets/NotificationIcons/profile-light.png new file mode 100644 index 00000000..a3bac71c Binary files /dev/null and b/Wino.Mail.WinUI/Assets/NotificationIcons/profile-light.png differ diff --git a/Wino.Mail.WinUI/Assets/Providers/Gmail.png b/Wino.Mail.WinUI/Assets/Providers/Gmail.png new file mode 100644 index 00000000..79dcff5b Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Providers/Gmail.png differ diff --git a/Wino.Mail.WinUI/Assets/Providers/IMAP4.png b/Wino.Mail.WinUI/Assets/Providers/IMAP4.png new file mode 100644 index 00000000..145023d0 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Providers/IMAP4.png differ diff --git a/Wino.Mail.WinUI/Assets/Providers/Office 365.png b/Wino.Mail.WinUI/Assets/Providers/Office 365.png new file mode 100644 index 00000000..8cecb7cb Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Providers/Office 365.png differ diff --git a/Wino.Mail.WinUI/Assets/Providers/Outlook.png b/Wino.Mail.WinUI/Assets/Providers/Outlook.png new file mode 100644 index 00000000..d1956be1 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Providers/Outlook.png differ diff --git a/Wino.Mail.WinUI/Assets/Providers/Yahoo.png b/Wino.Mail.WinUI/Assets/Providers/Yahoo.png new file mode 100644 index 00000000..7823af45 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Providers/Yahoo.png differ diff --git a/Wino.Mail.WinUI/Assets/ReleaseNotes/176.md b/Wino.Mail.WinUI/Assets/ReleaseNotes/176.md new file mode 100644 index 00000000..0e934216 --- /dev/null +++ b/Wino.Mail.WinUI/Assets/ReleaseNotes/176.md @@ -0,0 +1,33 @@ +# 🚀 Welcome to Wino Mail 1.7.6 + +This version brings bunch of UI improvements and bugfixes on top of the added features thanks to our community members. + +## Separated UI Zones + +Community liked the proposed designs for separated UI parts and it's implemented now thanks to [Tiktack](https://github.com/Tiktack) + +![Separated UI Zones](https://www.winomail.app/images/separatedzones.png) + +## Including Conversation History for Replies and Forwards + +Previously when you replied to an e-mail conversation history was not included into new draft. This was a limitation due to Quill editor we use as a composer editor but now thanks to [Tiktack](https://github.com/Tiktack) Wino now uses Jodit editor as a composer. It's able to render HTML as it is better. + +## HTML Signatures + +You can now copy your signature as HTML and paste directly into signature editor. This was asked by community and now is possible with the new Jodit composer. + +## Reworked Menu System + +Merged accounts will not list individual accounts below instead of inside the More folder menu item. + +## New IMAP and Gmail Folder Synchronization + +IMAP and Gmail folder synchronization mechanism is reworked. New code works faster and fixed couple parent-child relation issues with the folder. I hope this will also resolve a lot of people complaining some Gmail folders are not visible for them after the initial sync. + +## New Languages + +Thanks to our amazing community members Wino has more languages supported in this version with the help of Crowdin contributors. + +![Crowdin Contributors](https://www.winomail.app/images/contributors.png) + +Some of the translations are not completed yet, and Wino will fallback to English strings in case of the translation has not been translated yet. diff --git a/Wino.Mail.WinUI/Assets/SmallTile.scale-100.png b/Wino.Mail.WinUI/Assets/SmallTile.scale-100.png new file mode 100644 index 00000000..f0d52390 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/SmallTile.scale-100.png differ diff --git a/Wino.Mail.WinUI/Assets/SmallTile.scale-125.png b/Wino.Mail.WinUI/Assets/SmallTile.scale-125.png new file mode 100644 index 00000000..4a0404cf Binary files /dev/null and b/Wino.Mail.WinUI/Assets/SmallTile.scale-125.png differ diff --git a/Wino.Mail.WinUI/Assets/SmallTile.scale-150.png b/Wino.Mail.WinUI/Assets/SmallTile.scale-150.png new file mode 100644 index 00000000..f801334e Binary files /dev/null and b/Wino.Mail.WinUI/Assets/SmallTile.scale-150.png differ diff --git a/Wino.Mail.WinUI/Assets/SmallTile.scale-200.png b/Wino.Mail.WinUI/Assets/SmallTile.scale-200.png new file mode 100644 index 00000000..bb2c20c9 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/SmallTile.scale-200.png differ diff --git a/Wino.Mail.WinUI/Assets/SmallTile.scale-400.png b/Wino.Mail.WinUI/Assets/SmallTile.scale-400.png new file mode 100644 index 00000000..c931a5dd Binary files /dev/null and b/Wino.Mail.WinUI/Assets/SmallTile.scale-400.png differ diff --git a/Wino.Mail.WinUI/Assets/SplashScreen.scale-100.png b/Wino.Mail.WinUI/Assets/SplashScreen.scale-100.png new file mode 100644 index 00000000..23c8f147 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/SplashScreen.scale-100.png differ diff --git a/Wino.Mail.WinUI/Assets/SplashScreen.scale-125.png b/Wino.Mail.WinUI/Assets/SplashScreen.scale-125.png new file mode 100644 index 00000000..ceb2dff6 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/SplashScreen.scale-125.png differ diff --git a/Wino.Mail.WinUI/Assets/SplashScreen.scale-150.png b/Wino.Mail.WinUI/Assets/SplashScreen.scale-150.png new file mode 100644 index 00000000..885d9bc2 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/SplashScreen.scale-150.png differ diff --git a/Wino.Mail.WinUI/Assets/SplashScreen.scale-200.png b/Wino.Mail.WinUI/Assets/SplashScreen.scale-200.png index 32f486a8..58c8ca7c 100644 Binary files a/Wino.Mail.WinUI/Assets/SplashScreen.scale-200.png and b/Wino.Mail.WinUI/Assets/SplashScreen.scale-200.png differ diff --git a/Wino.Mail.WinUI/Assets/SplashScreen.scale-400.png b/Wino.Mail.WinUI/Assets/SplashScreen.scale-400.png new file mode 100644 index 00000000..fa77f2b7 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/SplashScreen.scale-400.png differ diff --git a/Wino.Mail.WinUI/Assets/Square150x150Logo.scale-100.png b/Wino.Mail.WinUI/Assets/Square150x150Logo.scale-100.png new file mode 100644 index 00000000..a5f235b8 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Square150x150Logo.scale-100.png differ diff --git a/Wino.Mail.WinUI/Assets/Square150x150Logo.scale-125.png b/Wino.Mail.WinUI/Assets/Square150x150Logo.scale-125.png new file mode 100644 index 00000000..be92b5ae Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Square150x150Logo.scale-125.png differ diff --git a/Wino.Mail.WinUI/Assets/Square150x150Logo.scale-150.png b/Wino.Mail.WinUI/Assets/Square150x150Logo.scale-150.png new file mode 100644 index 00000000..d0039797 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Square150x150Logo.scale-150.png differ diff --git a/Wino.Mail.WinUI/Assets/Square150x150Logo.scale-200.png b/Wino.Mail.WinUI/Assets/Square150x150Logo.scale-200.png index 53ee3777..430e6fa3 100644 Binary files a/Wino.Mail.WinUI/Assets/Square150x150Logo.scale-200.png and b/Wino.Mail.WinUI/Assets/Square150x150Logo.scale-200.png differ diff --git a/Wino.Mail.WinUI/Assets/Square150x150Logo.scale-400.png b/Wino.Mail.WinUI/Assets/Square150x150Logo.scale-400.png new file mode 100644 index 00000000..9726829b Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Square150x150Logo.scale-400.png differ diff --git a/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-lightunplated_targetsize-16.png b/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-lightunplated_targetsize-16.png new file mode 100644 index 00000000..4d6b9dfe Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-lightunplated_targetsize-16.png differ diff --git a/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-lightunplated_targetsize-24.png b/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-lightunplated_targetsize-24.png new file mode 100644 index 00000000..c0aa2ba3 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-lightunplated_targetsize-24.png differ diff --git a/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-lightunplated_targetsize-256.png b/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-lightunplated_targetsize-256.png new file mode 100644 index 00000000..7be00300 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-lightunplated_targetsize-256.png differ diff --git a/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-lightunplated_targetsize-32.png b/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-lightunplated_targetsize-32.png new file mode 100644 index 00000000..a6e4b0a2 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-lightunplated_targetsize-32.png differ diff --git a/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-lightunplated_targetsize-48.png b/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-lightunplated_targetsize-48.png new file mode 100644 index 00000000..07514cc2 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-lightunplated_targetsize-48.png differ diff --git a/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-unplated_targetsize-16.png b/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-unplated_targetsize-16.png new file mode 100644 index 00000000..4d6b9dfe Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-unplated_targetsize-16.png differ diff --git a/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-unplated_targetsize-256.png b/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-unplated_targetsize-256.png new file mode 100644 index 00000000..7be00300 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-unplated_targetsize-256.png differ diff --git a/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-unplated_targetsize-32.png b/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-unplated_targetsize-32.png new file mode 100644 index 00000000..a6e4b0a2 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-unplated_targetsize-32.png differ diff --git a/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-unplated_targetsize-48.png b/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-unplated_targetsize-48.png new file mode 100644 index 00000000..07514cc2 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Square44x44Logo.altform-unplated_targetsize-48.png differ diff --git a/Wino.Mail.WinUI/Assets/Square44x44Logo.scale-100.png b/Wino.Mail.WinUI/Assets/Square44x44Logo.scale-100.png new file mode 100644 index 00000000..7432521d Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Square44x44Logo.scale-100.png differ diff --git a/Wino.Mail.WinUI/Assets/Square44x44Logo.scale-125.png b/Wino.Mail.WinUI/Assets/Square44x44Logo.scale-125.png new file mode 100644 index 00000000..fe38dbdf Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Square44x44Logo.scale-125.png differ diff --git a/Wino.Mail.WinUI/Assets/Square44x44Logo.scale-150.png b/Wino.Mail.WinUI/Assets/Square44x44Logo.scale-150.png new file mode 100644 index 00000000..1ee950af Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Square44x44Logo.scale-150.png differ diff --git a/Wino.Mail.WinUI/Assets/Square44x44Logo.scale-200.png b/Wino.Mail.WinUI/Assets/Square44x44Logo.scale-200.png index f713bba6..807e9ed4 100644 Binary files a/Wino.Mail.WinUI/Assets/Square44x44Logo.scale-200.png and b/Wino.Mail.WinUI/Assets/Square44x44Logo.scale-200.png differ diff --git a/Wino.Mail.WinUI/Assets/Square44x44Logo.scale-400.png b/Wino.Mail.WinUI/Assets/Square44x44Logo.scale-400.png new file mode 100644 index 00000000..f4457476 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Square44x44Logo.scale-400.png differ diff --git a/Wino.Mail.WinUI/Assets/Square44x44Logo.targetsize-16.png b/Wino.Mail.WinUI/Assets/Square44x44Logo.targetsize-16.png new file mode 100644 index 00000000..9acb3cc8 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Square44x44Logo.targetsize-16.png differ diff --git a/Wino.Mail.WinUI/Assets/Square44x44Logo.targetsize-24.png b/Wino.Mail.WinUI/Assets/Square44x44Logo.targetsize-24.png new file mode 100644 index 00000000..c1e08a4f Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Square44x44Logo.targetsize-24.png differ diff --git a/Wino.Mail.WinUI/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/Wino.Mail.WinUI/Assets/Square44x44Logo.targetsize-24_altform-unplated.png index dc9f5bea..c0aa2ba3 100644 Binary files a/Wino.Mail.WinUI/Assets/Square44x44Logo.targetsize-24_altform-unplated.png and b/Wino.Mail.WinUI/Assets/Square44x44Logo.targetsize-24_altform-unplated.png differ diff --git a/Wino.Mail.WinUI/Assets/Square44x44Logo.targetsize-256.png b/Wino.Mail.WinUI/Assets/Square44x44Logo.targetsize-256.png new file mode 100644 index 00000000..37f8decd Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Square44x44Logo.targetsize-256.png differ diff --git a/Wino.Mail.WinUI/Assets/Square44x44Logo.targetsize-32.png b/Wino.Mail.WinUI/Assets/Square44x44Logo.targetsize-32.png new file mode 100644 index 00000000..93c856d9 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Square44x44Logo.targetsize-32.png differ diff --git a/Wino.Mail.WinUI/Assets/Square44x44Logo.targetsize-48.png b/Wino.Mail.WinUI/Assets/Square44x44Logo.targetsize-48.png new file mode 100644 index 00000000..a2ca3afc Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Square44x44Logo.targetsize-48.png differ diff --git a/Wino.Mail.WinUI/Assets/StoreLogo.backup.png b/Wino.Mail.WinUI/Assets/StoreLogo.backup.png new file mode 100644 index 00000000..7385b56c Binary files /dev/null and b/Wino.Mail.WinUI/Assets/StoreLogo.backup.png differ diff --git a/Wino.Mail.WinUI/Assets/StoreLogo.scale-100.png b/Wino.Mail.WinUI/Assets/StoreLogo.scale-100.png new file mode 100644 index 00000000..4c4b4b34 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/StoreLogo.scale-100.png differ diff --git a/Wino.Mail.WinUI/Assets/StoreLogo.scale-125.png b/Wino.Mail.WinUI/Assets/StoreLogo.scale-125.png new file mode 100644 index 00000000..1c325127 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/StoreLogo.scale-125.png differ diff --git a/Wino.Mail.WinUI/Assets/StoreLogo.scale-150.png b/Wino.Mail.WinUI/Assets/StoreLogo.scale-150.png new file mode 100644 index 00000000..bb194ef7 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/StoreLogo.scale-150.png differ diff --git a/Wino.Mail.WinUI/Assets/StoreLogo.scale-200.png b/Wino.Mail.WinUI/Assets/StoreLogo.scale-200.png new file mode 100644 index 00000000..b77a5ddc Binary files /dev/null and b/Wino.Mail.WinUI/Assets/StoreLogo.scale-200.png differ diff --git a/Wino.Mail.WinUI/Assets/StoreLogo.scale-400.png b/Wino.Mail.WinUI/Assets/StoreLogo.scale-400.png new file mode 100644 index 00000000..8d0a133e Binary files /dev/null and b/Wino.Mail.WinUI/Assets/StoreLogo.scale-400.png differ diff --git a/Wino.Mail.WinUI/Assets/Thumbnails/airbnb.com.png b/Wino.Mail.WinUI/Assets/Thumbnails/airbnb.com.png new file mode 100644 index 00000000..9713a7af Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Thumbnails/airbnb.com.png differ diff --git a/Wino.Mail.WinUI/Assets/Thumbnails/apple.com.png b/Wino.Mail.WinUI/Assets/Thumbnails/apple.com.png new file mode 100644 index 00000000..18621ea7 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Thumbnails/apple.com.png differ diff --git a/Wino.Mail.WinUI/Assets/Thumbnails/google.com.png b/Wino.Mail.WinUI/Assets/Thumbnails/google.com.png new file mode 100644 index 00000000..5af3ede9 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Thumbnails/google.com.png differ diff --git a/Wino.Mail.WinUI/Assets/Thumbnails/microsoft.com.png b/Wino.Mail.WinUI/Assets/Thumbnails/microsoft.com.png new file mode 100644 index 00000000..e0a0d837 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Thumbnails/microsoft.com.png differ diff --git a/Wino.Mail.WinUI/Assets/Thumbnails/steampowered.com.png b/Wino.Mail.WinUI/Assets/Thumbnails/steampowered.com.png new file mode 100644 index 00000000..a5d6087f Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Thumbnails/steampowered.com.png differ diff --git a/Wino.Mail.WinUI/Assets/Thumbnails/uber.com.png b/Wino.Mail.WinUI/Assets/Thumbnails/uber.com.png new file mode 100644 index 00000000..5dbb4ea8 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Thumbnails/uber.com.png differ diff --git a/Wino.Mail.WinUI/Assets/Thumbnails/youtube.com.png b/Wino.Mail.WinUI/Assets/Thumbnails/youtube.com.png new file mode 100644 index 00000000..0df5bd9b Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Thumbnails/youtube.com.png differ diff --git a/Wino.Mail.WinUI/Assets/Wide310x150Logo.scale-100.png b/Wino.Mail.WinUI/Assets/Wide310x150Logo.scale-100.png new file mode 100644 index 00000000..f330133d Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Wide310x150Logo.scale-100.png differ diff --git a/Wino.Mail.WinUI/Assets/Wide310x150Logo.scale-125.png b/Wino.Mail.WinUI/Assets/Wide310x150Logo.scale-125.png new file mode 100644 index 00000000..e4656fa7 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Wide310x150Logo.scale-125.png differ diff --git a/Wino.Mail.WinUI/Assets/Wide310x150Logo.scale-150.png b/Wino.Mail.WinUI/Assets/Wide310x150Logo.scale-150.png new file mode 100644 index 00000000..884084b3 Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Wide310x150Logo.scale-150.png differ diff --git a/Wino.Mail.WinUI/Assets/Wide310x150Logo.scale-200.png b/Wino.Mail.WinUI/Assets/Wide310x150Logo.scale-200.png index 8b4a5d0d..23c8f147 100644 Binary files a/Wino.Mail.WinUI/Assets/Wide310x150Logo.scale-200.png and b/Wino.Mail.WinUI/Assets/Wide310x150Logo.scale-200.png differ diff --git a/Wino.Mail.WinUI/Assets/Wide310x150Logo.scale-400.png b/Wino.Mail.WinUI/Assets/Wide310x150Logo.scale-400.png new file mode 100644 index 00000000..58c8ca7c Binary files /dev/null and b/Wino.Mail.WinUI/Assets/Wide310x150Logo.scale-400.png differ diff --git a/Wino.Mail.WinUI/Assets/WinoIcons.ttf b/Wino.Mail.WinUI/Assets/WinoIcons.ttf new file mode 100644 index 00000000..505f058a Binary files /dev/null and b/Wino.Mail.WinUI/Assets/WinoIcons.ttf differ diff --git a/Wino.Mail.WinUI/BackgroundImages/Acrylic.jpg b/Wino.Mail.WinUI/BackgroundImages/Acrylic.jpg new file mode 100644 index 00000000..48c3b7d9 Binary files /dev/null and b/Wino.Mail.WinUI/BackgroundImages/Acrylic.jpg differ diff --git a/Wino.Mail.WinUI/BackgroundImages/Clouds.jpg b/Wino.Mail.WinUI/BackgroundImages/Clouds.jpg new file mode 100644 index 00000000..f643572d Binary files /dev/null and b/Wino.Mail.WinUI/BackgroundImages/Clouds.jpg differ diff --git a/Wino.Mail.WinUI/BackgroundImages/Forest.jpg b/Wino.Mail.WinUI/BackgroundImages/Forest.jpg new file mode 100644 index 00000000..aa58e6af Binary files /dev/null and b/Wino.Mail.WinUI/BackgroundImages/Forest.jpg differ diff --git a/Wino.Mail.WinUI/BackgroundImages/Garden.jpg b/Wino.Mail.WinUI/BackgroundImages/Garden.jpg new file mode 100644 index 00000000..eaf1d05a Binary files /dev/null and b/Wino.Mail.WinUI/BackgroundImages/Garden.jpg differ diff --git a/Wino.Mail.WinUI/BackgroundImages/Mica.jpg b/Wino.Mail.WinUI/BackgroundImages/Mica.jpg new file mode 100644 index 00000000..10519a41 Binary files /dev/null and b/Wino.Mail.WinUI/BackgroundImages/Mica.jpg differ diff --git a/Wino.Mail.WinUI/BackgroundImages/Nighty.jpg b/Wino.Mail.WinUI/BackgroundImages/Nighty.jpg new file mode 100644 index 00000000..b79c8f1b Binary files /dev/null and b/Wino.Mail.WinUI/BackgroundImages/Nighty.jpg differ diff --git a/Wino.Mail.WinUI/BackgroundImages/Snowflake.jpg b/Wino.Mail.WinUI/BackgroundImages/Snowflake.jpg new file mode 100644 index 00000000..f5129640 Binary files /dev/null and b/Wino.Mail.WinUI/BackgroundImages/Snowflake.jpg differ diff --git a/Wino.Mail.WinUI/BasePage.cs b/Wino.Mail.WinUI/BasePage.cs new file mode 100644 index 00000000..57474c96 --- /dev/null +++ b/Wino.Mail.WinUI/BasePage.cs @@ -0,0 +1,84 @@ +using System; +using System.Diagnostics; +using CommunityToolkit.Mvvm.Messaging; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Navigation; +using Wino.Core.Messages.Shell; +using Wino.Core.WinUI; +using Wino.Mail.ViewModels; +using Wino.Mail.WinUI; + +namespace Wino +{ + public class BasePage : Page, IRecipient + { + public UIElement ShellContent + { + get { return (UIElement)GetValue(ShellContentProperty); } + set { SetValue(ShellContentProperty, value); } + } + + public static readonly DependencyProperty ShellContentProperty = DependencyProperty.Register(nameof(ShellContent), typeof(UIElement), typeof(BasePage), new PropertyMetadata(null)); + + public void Receive(LanguageChanged message) + { + OnLanguageChanged(); + } + + public virtual void OnLanguageChanged() { } + } + + public abstract class BasePage : BasePage where T : BaseViewModel + { + public T ViewModel { get; } = App.Current.Services.GetService(); + + protected BasePage() + { + // UWP and WinUI Dispatchers are different. +#if NET8_0 + ViewModel.Dispatcher = new WinAppDispatcher(DispatcherQueue); +#else + ViewModel.Dispatcher = new UWPDispatcher(Dispatcher); +#endif + } + + ~BasePage() + { + Debug.WriteLine($"Disposed {this.GetType().Name}"); + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + base.OnNavigatedTo(e); + + var mode = GetNavigationMode(e.NavigationMode); + var parameter = e.Parameter; + + WeakReferenceMessenger.Default.UnregisterAll(this); + WeakReferenceMessenger.Default.RegisterAll(this); + + ViewModel.OnNavigatedTo(mode, parameter); + } + + protected override void OnNavigatingFrom(NavigatingCancelEventArgs e) + { + base.OnNavigatingFrom(e); + + var mode = GetNavigationMode(e.NavigationMode); + var parameter = e.Parameter; + + WeakReferenceMessenger.Default.UnregisterAll(this); + + ViewModel.OnNavigatedFrom(mode, parameter); + + GC.Collect(); + } + + private Core.Domain.Models.Navigation.NavigationMode GetNavigationMode(NavigationMode mode) + { + return (Core.Domain.Models.Navigation.NavigationMode)mode; + } + } +} diff --git a/Wino.Mail.WinUI/Behaviors/BindableCommandBarBehavior.cs b/Wino.Mail.WinUI/Behaviors/BindableCommandBarBehavior.cs new file mode 100644 index 00000000..cc0b1737 --- /dev/null +++ b/Wino.Mail.WinUI/Behaviors/BindableCommandBarBehavior.cs @@ -0,0 +1,205 @@ +using System.Collections; +using System.Collections.Specialized; +using System.Windows.Input; + +using Microsoft.Xaml.Interactivity; +using Wino.Controls; +using Wino.Core.Domain.Models.Menus; +using Wino.Helpers; + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Controls.Primitives; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Controls.Primitives; + +#endif +namespace Wino.Behaviors +{ + public class BindableCommandBarBehavior : Behavior + { + public static readonly DependencyProperty PrimaryCommandsProperty = DependencyProperty.Register( + "PrimaryCommands", typeof(object), typeof(BindableCommandBarBehavior), + new PropertyMetadata(null, UpdateCommands)); + + public static readonly DependencyProperty ItemTemplateSelectorProperty = DependencyProperty.Register( + "ItemTemplateSelector", typeof(DataTemplateSelector), typeof(BindableCommandBarBehavior), + new PropertyMetadata(null, null)); + + public ICommand ItemClickedCommand + { + get { return (ICommand)GetValue(ItemClickedCommandProperty); } + set { SetValue(ItemClickedCommandProperty, value); } + } + + public static readonly DependencyProperty ItemClickedCommandProperty = DependencyProperty.Register(nameof(ItemClickedCommand), typeof(ICommand), typeof(BindableCommandBarBehavior), new PropertyMetadata(null)); + + public DataTemplateSelector ItemTemplateSelector + { + get { return (DataTemplateSelector)GetValue(ItemTemplateSelectorProperty); } + set { SetValue(ItemTemplateSelectorProperty, value); } + } + + public object PrimaryCommands + { + get { return GetValue(PrimaryCommandsProperty); } + set { SetValue(PrimaryCommandsProperty, value); } + } + + protected override void OnDetaching() + { + base.OnDetaching(); + + AttachChanges(false); + + if (PrimaryCommands is IEnumerable enumerable) + { + foreach (var item in enumerable) + { + if (item is ButtonBase button) + { + button.Click -= Button_Click; + } + } + } + } + + private void UpdatePrimaryCommands() + { + if (AssociatedObject == null) + return; + + if (PrimaryCommands == null) + return; + + if (AssociatedObject.PrimaryCommands is IEnumerable enumerableObjects) + { + foreach (var item in enumerableObjects) + { + if (item is ButtonBase button) + { + button.Click -= Button_Click; + } + } + } + + if (AssociatedObject.SecondaryCommands is IEnumerable secondaryObject) + { + foreach (var item in secondaryObject) + { + if (item is ButtonBase button) + { + button.Click -= Button_Click; + } + } + } + + AssociatedObject.PrimaryCommands.Clear(); + AssociatedObject.SecondaryCommands.Clear(); + + if (!(PrimaryCommands is IEnumerable enumerable)) return; + + foreach (var command in enumerable) + { + if (command is MailOperationMenuItem mailOperationMenuItem) + { + ICommandBarElement menuItem = null; + + if (mailOperationMenuItem.Operation == Core.Domain.Enums.MailOperation.Seperator) + { + menuItem = new AppBarSeparator(); + } + else + { + var label = XamlHelpers.GetOperationString(mailOperationMenuItem.Operation); + menuItem = new AppBarButton + { + Icon = new WinoFontIcon() { Glyph = ControlConstants.WinoIconFontDictionary[XamlHelpers.GetWinoIconGlyph(mailOperationMenuItem.Operation)] }, + Label = label, + LabelPosition = string.IsNullOrWhiteSpace(label) ? CommandBarLabelPosition.Collapsed : CommandBarLabelPosition.Default, + DataContext = mailOperationMenuItem, + }; + + ((AppBarButton)menuItem).Click -= Button_Click; + ((AppBarButton)menuItem).Click += Button_Click; + } + + if (mailOperationMenuItem.IsSecondaryMenuPreferred) + { + AssociatedObject.SecondaryCommands.Add(menuItem); + } + else + { + AssociatedObject.PrimaryCommands.Add(menuItem); + } + } + + //if (dependencyObject is ICommandBarElement icommandBarElement) + //{ + // if (dependencyObject is ButtonBase button) + // { + // button.Click -= Button_Click; + // button.Click += Button_Click; + // } + + // if (command is MailOperationMenuItem mailOperationMenuItem) + // { + + // } + //} + } + } + + private void Button_Click(object sender, RoutedEventArgs e) + { + ItemClickedCommand?.Execute(((ButtonBase)sender).DataContext); + } + + protected override void OnAttached() + { + base.OnAttached(); + + AttachChanges(true); + + UpdatePrimaryCommands(); + } + + private void PrimaryCommandsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + UpdatePrimaryCommands(); + } + + private static void UpdateCommands(DependencyObject dependencyObject, + DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) + { + if (!(dependencyObject is BindableCommandBarBehavior behavior)) return; + + if (dependencyPropertyChangedEventArgs.OldValue is INotifyCollectionChanged oldList) + { + oldList.CollectionChanged -= behavior.PrimaryCommandsCollectionChanged; + } + + behavior.AttachChanges(true); + behavior.UpdatePrimaryCommands(); + } + + private void AttachChanges(bool register) + { + if (PrimaryCommands is null) return; + + if (PrimaryCommands is INotifyCollectionChanged collectionChanged) + { + if (register) + { + collectionChanged.CollectionChanged -= PrimaryCommandsCollectionChanged; + collectionChanged.CollectionChanged += PrimaryCommandsCollectionChanged; + } + else + collectionChanged.CollectionChanged -= PrimaryCommandsCollectionChanged; + } + } + } +} diff --git a/Wino.Mail.WinUI/Behaviors/CreateMailNavigationItemBehavior.cs b/Wino.Mail.WinUI/Behaviors/CreateMailNavigationItemBehavior.cs new file mode 100644 index 00000000..02452c57 --- /dev/null +++ b/Wino.Mail.WinUI/Behaviors/CreateMailNavigationItemBehavior.cs @@ -0,0 +1,92 @@ +using System.Collections.ObjectModel; +using Microsoft.Xaml.Interactivity; + +using Wino.Controls; +using Wino.Core.MenuItems; + +#if NET8_0 +using Microsoft.UI.Xaml; +#else +using Windows.UI.Xaml; +#endif + +namespace Wino.Behaviors +{ + public class CreateMailNavigationItemBehavior : Behavior + { + public MenuItemBase SelectedMenuItem + { + get { return (MenuItemBase)GetValue(SelectedMenuItemProperty); } + set { SetValue(SelectedMenuItemProperty, value); } + } + + public ObservableCollection MenuItems + { + get { return (ObservableCollection)GetValue(MenuItemsProperty); } + set { SetValue(MenuItemsProperty, value); } + } + + public static readonly DependencyProperty MenuItemsProperty = DependencyProperty.Register(nameof(MenuItems), typeof(ObservableCollection), typeof(CreateMailNavigationItemBehavior), new PropertyMetadata(null, OnMenuItemsChanged)); + public static readonly DependencyProperty SelectedMenuItemProperty = DependencyProperty.Register(nameof(SelectedMenuItem), typeof(MenuItemBase), typeof(CreateMailNavigationItemBehavior), new PropertyMetadata(null, OnSelectedMenuItemChanged)); + + public CreateMailNavigationItemBehavior() + { + + } + + protected override void OnAttached() + { + base.OnAttached(); + } + + protected override void OnDetaching() + { + base.OnDetaching(); + } + + private static void OnMenuItemsChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) + { + if (dependencyObject is CreateMailNavigationItemBehavior behavior) + { + if (dependencyPropertyChangedEventArgs.NewValue != null) + behavior.RegisterMenuItemChanges(); + + behavior.ManageAccounts(); + } + } + + private void RegisterMenuItemChanges() + { + if (MenuItems != null) + { + MenuItems.CollectionChanged -= MenuCollectionUpdated; + MenuItems.CollectionChanged += MenuCollectionUpdated; + } + } + + private void MenuCollectionUpdated(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + ManageAccounts(); + } + + private static void OnSelectedMenuItemChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) + { + if (dependencyObject is CreateMailNavigationItemBehavior behavior) + { + behavior.ManageAccounts(); + } + } + + private void ManageAccounts() + { + if (MenuItems == null) return; + + AssociatedObject.MenuItems.Clear(); + + if (SelectedMenuItem == null) + { + // ?? + } + } + } +} diff --git a/Wino.Mail.WinUI/Controls/AccountNavigationItem.cs b/Wino.Mail.WinUI/Controls/AccountNavigationItem.cs new file mode 100644 index 00000000..0676da6e --- /dev/null +++ b/Wino.Mail.WinUI/Controls/AccountNavigationItem.cs @@ -0,0 +1,80 @@ +using System.Numerics; +using Microsoft.UI.Xaml.Controls; + +using Wino.Core.Domain.Interfaces; + + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Shapes; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Shapes; +#endif +namespace Wino.Controls +{ + public class AccountNavigationItem : WinoNavigationViewItem + { + + public static readonly DependencyProperty IsActiveAccountProperty = DependencyProperty.Register(nameof(IsActiveAccount), typeof(bool), typeof(AccountNavigationItem), new PropertyMetadata(false, new PropertyChangedCallback(OnIsActiveAccountChanged))); + public static readonly DependencyProperty BindingDataProperty = DependencyProperty.Register(nameof(BindingData), typeof(IAccountMenuItem), typeof(AccountNavigationItem), new PropertyMetadata(null)); + + + public bool IsActiveAccount + { + get { return (bool)GetValue(IsActiveAccountProperty); } + set { SetValue(IsActiveAccountProperty, value); } + } + + public IAccountMenuItem BindingData + { + get { return (IAccountMenuItem)GetValue(BindingDataProperty); } + set { SetValue(BindingDataProperty, value); } + } + + private const string PART_NavigationViewItemMenuItemsHost = "NavigationViewItemMenuItemsHost"; + private const string PART_SelectionIndicator = "CustomSelectionIndicator"; + + private ItemsRepeater _itemsRepeater; + private Rectangle _selectionIndicator; + + public AccountNavigationItem() + { + DefaultStyleKey = typeof(AccountNavigationItem); + } + + protected override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + _itemsRepeater = GetTemplateChild(PART_NavigationViewItemMenuItemsHost) as ItemsRepeater; + _selectionIndicator = GetTemplateChild(PART_SelectionIndicator) as Rectangle; + + if (_itemsRepeater == null) return; + + (_itemsRepeater.Layout as StackLayout).Spacing = 0; + + UpdateSelectionBorder(); + } + + private static void OnIsActiveAccountChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) + { + if (obj is AccountNavigationItem control) + control.UpdateSelectionBorder(); + } + + private void UpdateSelectionBorder() + { + if (_selectionIndicator == null) return; + + // Adjsuting Margin in the styles are not possible due to the fact that we use the same tempalte for different types of menu items. + // Account templates listed under merged accounts will have Padding of 44. We must adopt to that. + + bool hasParentMenuItem = BindingData is IAccountMenuItem accountMenuItem && accountMenuItem.ParentMenuItem != null; + + _selectionIndicator.Margin = !hasParentMenuItem ? new Thickness(-44, 12, 0, 12) : new Thickness(-60, 12, -60, 12); + _selectionIndicator.Scale = IsActiveAccount ? new Vector3(1, 1, 1) : new Vector3(0, 0, 0); + _selectionIndicator.Visibility = IsActiveAccount ? Visibility.Visible : Visibility.Collapsed; + } + } +} diff --git a/Wino.Mail.WinUI/Controls/Advanced/WinoAppTitleBar.xaml b/Wino.Mail.WinUI/Controls/Advanced/WinoAppTitleBar.xaml new file mode 100644 index 00000000..63e166a5 --- /dev/null +++ b/Wino.Mail.WinUI/Controls/Advanced/WinoAppTitleBar.xaml @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wino.Mail.WinUI/Controls/Advanced/WinoAppTitleBar.xaml.cs b/Wino.Mail.WinUI/Controls/Advanced/WinoAppTitleBar.xaml.cs new file mode 100644 index 00000000..a6817184 --- /dev/null +++ b/Wino.Mail.WinUI/Controls/Advanced/WinoAppTitleBar.xaml.cs @@ -0,0 +1,177 @@ +using Windows.Foundation; +using Wino.Core.WinUI.Services; +using Microsoft.Extensions.DependencyInjection; +using Wino.Mail.WinUI; + + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +#endif +namespace Wino.Controls.Advanced +{ + public sealed partial class WinoAppTitleBar : UserControl + { + private IAppShellService _appShellService = App.Current.Services.GetService(); + + public event TypedEventHandler BackButtonClicked; + + public string CoreWindowText + { + get { return (string)GetValue(CoreWindowTextProperty); } + set { SetValue(CoreWindowTextProperty, value); } + } + + public double SystemReserved + { + get { return (double)GetValue(SystemReservedProperty); } + set { SetValue(SystemReservedProperty, value); } + } + + public UIElement ShellFrameContent + { + get { return (UIElement)GetValue(ShellFrameContentProperty); } + set { SetValue(ShellFrameContentProperty, value); } + } + + public Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode NavigationViewDisplayMode + { + get { return (Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode)GetValue(NavigationViewDisplayModeProperty); } + set { SetValue(NavigationViewDisplayModeProperty, value); } + } + + public bool IsNavigationPaneOpen + { + get { return (bool)GetValue(IsNavigationPaneOpenProperty); } + set { SetValue(IsNavigationPaneOpenProperty, value); } + } + + public double OpenPaneLength + { + get { return (double)GetValue(OpenPaneLengthProperty); } + set { SetValue(OpenPaneLengthProperty, value); } + } + + public bool IsBackButtonVisible + { + get { return (bool)GetValue(IsBackButtonVisibleProperty); } + set { SetValue(IsBackButtonVisibleProperty, value); } + } + + public bool IsReaderNarrowed + { + get { return (bool)GetValue(IsReaderNarrowedProperty); } + set { SetValue(IsReaderNarrowedProperty, value); } + } + + public bool IsRenderingPaneVisible + { + get { return (bool)GetValue(IsRenderingPaneVisibleProperty); } + set { SetValue(IsRenderingPaneVisibleProperty, value); } + } + + public static readonly DependencyProperty IsRenderingPaneVisibleProperty = DependencyProperty.Register(nameof(IsRenderingPaneVisible), typeof(bool), typeof(WinoAppTitleBar), new PropertyMetadata(false, OnDrawingPropertyChanged)); + public static readonly DependencyProperty IsReaderNarrowedProperty = DependencyProperty.Register(nameof(IsReaderNarrowed), typeof(bool), typeof(WinoAppTitleBar), new PropertyMetadata(false, OnIsReaderNarrowedChanged)); + public static readonly DependencyProperty IsBackButtonVisibleProperty = DependencyProperty.Register(nameof(IsBackButtonVisible), typeof(bool), typeof(WinoAppTitleBar), new PropertyMetadata(false, OnDrawingPropertyChanged)); + public static readonly DependencyProperty OpenPaneLengthProperty = DependencyProperty.Register(nameof(OpenPaneLength), typeof(double), typeof(WinoAppTitleBar), new PropertyMetadata(0d, OnDrawingPropertyChanged)); + public static readonly DependencyProperty IsNavigationPaneOpenProperty = DependencyProperty.Register(nameof(IsNavigationPaneOpen), typeof(bool), typeof(WinoAppTitleBar), new PropertyMetadata(false, OnDrawingPropertyChanged)); + public static readonly DependencyProperty NavigationViewDisplayModeProperty = DependencyProperty.Register(nameof(NavigationViewDisplayMode), typeof(Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode), typeof(WinoAppTitleBar), new PropertyMetadata(Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Compact, OnDrawingPropertyChanged)); + public static readonly DependencyProperty ShellFrameContentProperty = DependencyProperty.Register(nameof(ShellFrameContent), typeof(UIElement), typeof(WinoAppTitleBar), new PropertyMetadata(null, OnDrawingPropertyChanged)); + public static readonly DependencyProperty SystemReservedProperty = DependencyProperty.Register(nameof(SystemReserved), typeof(double), typeof(WinoAppTitleBar), new PropertyMetadata(0, OnDrawingPropertyChanged)); + public static readonly DependencyProperty CoreWindowTextProperty = DependencyProperty.Register(nameof(CoreWindowText), typeof(string), typeof(WinoAppTitleBar), new PropertyMetadata(string.Empty, OnDrawingPropertyChanged)); + public static readonly DependencyProperty ReadingPaneLengthProperty = DependencyProperty.Register(nameof(ReadingPaneLength), typeof(double), typeof(WinoAppTitleBar), new PropertyMetadata(420d, OnDrawingPropertyChanged)); + + + public double ReadingPaneLength + { + get { return (double)GetValue(ReadingPaneLengthProperty); } + set { SetValue(ReadingPaneLengthProperty, value); } + } + + private static void OnIsReaderNarrowedChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) + { + if (obj is WinoAppTitleBar bar) + { + bar.DrawTitleBar(); + } + } + + private static void OnDrawingPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) + { + if (obj is WinoAppTitleBar bar) + { + bar.DrawTitleBar(); + } + } + + private void DrawTitleBar() + { + UpdateLayout(); + + CoreWindowTitleTextBlock.Visibility = Visibility.Collapsed; + ShellContentContainer.Width = double.NaN; + ShellContentContainer.Margin = new Thickness(0, 0, 0, 0); + ShellContentContainer.HorizontalAlignment = HorizontalAlignment.Stretch; + + EmptySpaceWidth.Width = new GridLength(1, GridUnitType.Star); + + // Menu is not visible. + if (NavigationViewDisplayMode == Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Minimal) + { + + } + else if (NavigationViewDisplayMode == Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Compact) + { + // Icons are visible. + + if (!IsReaderNarrowed) + { + ShellContentContainer.HorizontalAlignment = HorizontalAlignment.Left; + ShellContentContainer.Width = ReadingPaneLength; + } + } + else if (NavigationViewDisplayMode == Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Expanded) + { + if (IsNavigationPaneOpen) + { + CoreWindowTitleTextBlock.Visibility = Visibility.Visible; + + // LMargin = OpenPaneLength - LeftMenuStackPanel + ShellContentContainer.Margin = new Thickness(OpenPaneLength - LeftMenuStackPanel.ActualSize.X, 0, 0, 0); + + if (!IsReaderNarrowed) + { + ShellContentContainer.HorizontalAlignment = HorizontalAlignment.Left; + ShellContentContainer.Width = ReadingPaneLength; + } + } + else + { + EmptySpaceWidth.Width = new GridLength(ReadingPaneLength, GridUnitType.Pixel); + } + } + } + + public WinoAppTitleBar() + { + InitializeComponent(); + + _appShellService.AppWindow.SetTitleBar(dragbar); + } + + private void BackClicked(object sender, RoutedEventArgs e) + { + BackButtonClicked?.Invoke(this, e); + } + + private void PaneClicked(object sender, RoutedEventArgs e) + { + IsNavigationPaneOpen = !IsNavigationPaneOpen; + } + + private void TitlebarSizeChanged(object sender, SizeChangedEventArgs e) => DrawTitleBar(); + } +} diff --git a/Wino.Mail.WinUI/Controls/Advanced/WinoListView.cs b/Wino.Mail.WinUI/Controls/Advanced/WinoListView.cs new file mode 100644 index 00000000..9a96414e --- /dev/null +++ b/Wino.Mail.WinUI/Controls/Advanced/WinoListView.cs @@ -0,0 +1,390 @@ +using System; +using System.Linq; +using System.Windows.Input; +using CommunityToolkit.Mvvm.Messaging; +using Microsoft.UI.Xaml.Controls; +using MoreLinq; +using Serilog; + +using Wino.Core.Domain.Enums; +using Wino.Core.Domain.Models.MailItem; +using Wino.Extensions; +using Wino.Mail.ViewModels.Data; +using Wino.Mail.ViewModels.Messages; + + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Input; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Input; +#endif +namespace Wino.Controls.Advanced +{ + /// + /// Custom ListView control that handles multiple selection with Extended/Multiple selection mode + /// and supports threads. + /// + public class WinoListView : ListView, IDisposable + { + private ILogger logger = Log.ForContext(); + + private const string PART_ScrollViewer = "ScrollViewer"; + private ScrollViewer internalScrollviewer; + + /// + /// Gets or sets whether this ListView belongs to thread items. + /// This is important for detecting selected items etc. + /// + public bool IsThreadListView + { + get { return (bool)GetValue(IsThreadListViewProperty); } + set { SetValue(IsThreadListViewProperty, value); } + } + + public ICommand ItemDeletedCommand + { + get { return (ICommand)GetValue(ItemDeletedCommandProperty); } + set { SetValue(ItemDeletedCommandProperty, value); } + } + + public ICommand LoadMoreCommand + { + get { return (ICommand)GetValue(LoadMoreCommandProperty); } + set { SetValue(LoadMoreCommandProperty, value); } + } + + public static readonly DependencyProperty LoadMoreCommandProperty = DependencyProperty.Register(nameof(LoadMoreCommand), typeof(ICommand), typeof(WinoListView), new PropertyMetadata(null)); + public static readonly DependencyProperty IsThreadListViewProperty = DependencyProperty.Register(nameof(IsThreadListView), typeof(bool), typeof(WinoListView), new PropertyMetadata(false)); + public static readonly DependencyProperty ItemDeletedCommandProperty = DependencyProperty.Register(nameof(ItemDeletedCommand), typeof(ICommand), typeof(WinoListView), new PropertyMetadata(null)); + + public WinoListView() + { + CanDragItems = true; + IsItemClickEnabled = true; + IsMultiSelectCheckBoxEnabled = true; + IsRightTapEnabled = true; + SelectionMode = ListViewSelectionMode.Extended; + ShowsScrollingPlaceholders = false; + SingleSelectionFollowsFocus = true; + + DragItemsCompleted += ItemDragCompleted; + DragItemsStarting += ItemDragStarting; + SelectionChanged += SelectedItemsChanged; + ItemClick += MailItemClicked; + ProcessKeyboardAccelerators += ProcessDelKey; + } + + protected override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + internalScrollviewer = GetTemplateChild(PART_ScrollViewer) as ScrollViewer; + + if (internalScrollviewer == null) + { + logger.Warning("WinoListView does not have an internal ScrollViewer. Infinite scrolling behavior might be effected."); + return; + } + + internalScrollviewer.ViewChanged -= InternalScrollVeiwerViewChanged; + internalScrollviewer.ViewChanged += InternalScrollVeiwerViewChanged; + } + + private double lastestRaisedOffset = 0; + private int lastItemSize = 0; + + // TODO: This is buggy. Does not work all the time. Debug. + + private void InternalScrollVeiwerViewChanged(object sender, ScrollViewerViewChangedEventArgs e) + { + if (internalScrollviewer == null) return; + + // No need to raise init request if there are no items in the list. + if (Items.Count == 0) return; + + // If the scrolling is finished, check the current viewport height. + if (e.IsIntermediate) + { + var currentOffset = internalScrollviewer.VerticalOffset; + var maxOffset = internalScrollviewer.ScrollableHeight; + + if (currentOffset + 10 >= maxOffset && lastestRaisedOffset != maxOffset && Items.Count != lastItemSize) + { + // We must load more. + lastestRaisedOffset = maxOffset; + lastItemSize = Items.Count; + + LoadMoreCommand?.Execute(null); + } + } + } + + private void ProcessDelKey(UIElement sender, ProcessKeyboardAcceleratorEventArgs args) + { + if (args.Key == Windows.System.VirtualKey.Delete) + { + args.Handled = true; + + ItemDeletedCommand?.Execute((int)MailOperation.SoftDelete); + } + } + + private void ItemDragCompleted(ListViewBase sender, DragItemsCompletedEventArgs args) + { + if (args.Items.Any(a => a is MailItemViewModel)) + { + args.Items.Cast().ForEach(a => a.IsCustomFocused = false); + } + } + + private void ItemDragStarting(object sender, DragItemsStartingEventArgs args) + { + // Dragging multiple mails from different accounts/folders are supported with the condition below: + // All mails belongs to the drag will be matched on the dropped folder's account. + // Meaning that if users drag 1 mail from Account A/Inbox and 1 mail from Account B/Inbox, + // and drop to Account A/Inbox, the mail from Account B/Inbox will NOT be moved. + + if (IsThreadListView) + { + var allItems = args.Items.Cast(); + + // Highlight all items + allItems.ForEach(a => a.IsCustomFocused = true); + + // Set native drag arg properties. + + var dragPackage = new MailDragPackage(allItems.Cast()); + + args.Data.Properties.Add(nameof(MailDragPackage), dragPackage); + } + else + { + var dragPackage = new MailDragPackage(args.Items.Cast()); + + args.Data.Properties.Add(nameof(MailDragPackage), dragPackage); + } + } + + private void MailItemClicked(object sender, ItemClickEventArgs e) + { + if (e.ClickedItem is ThreadMailItemViewModel clickedThread) + { + clickedThread.IsThreadExpanded = !clickedThread.IsThreadExpanded; + + if (!clickedThread.IsThreadExpanded) + { + SelectedItems.Clear(); + } + } + } + + public void ChangeSelectionMode(ListViewSelectionMode selectionMode) + { + SelectionMode = selectionMode; + + if (!IsThreadListView) + { + Items.Where(a => a is ThreadMailItemViewModel).Cast().ForEach(c => + { + var threadListView = GetThreadInternalListView(c); + + if (threadListView != null) + { + threadListView.SelectionMode = selectionMode; + } + }); + } + } + + /// + /// Finds the container for given mail item and adds it to selected items. + /// + /// Mail to be added to selected items. + /// Whether selection was successful or not. + public bool SelectMailItemContainer(MailItemViewModel mailItemViewModel) + { + var itemContainer = ContainerFromItem(mailItemViewModel); + + // This item might be in thread container. + if (itemContainer == null) + { + bool found = false; + + Items.OfType().ForEach(c => + { + if (!found) + { + var threadListView = GetThreadInternalListView(c); + + if (threadListView != null) + found = threadListView.SelectMailItemContainer(mailItemViewModel); + } + }); + + return found; + } + + SelectedItems.Add(mailItemViewModel); + return true; + } + + /// + /// Recursively clears all selections except the given mail. + /// + /// Exceptional mail item to be not unselected. + /// Whether expansion states of thread containers should stay as it is or not. + public void ClearSelections(MailItemViewModel exceptViewModel = null, bool preserveThreadExpanding = false) + { + SelectedItems.Clear(); + + Items.Where(a => a is ThreadMailItemViewModel).Cast().ForEach(c => + { + var threadListView = GetThreadInternalListView(c); + + if (threadListView == null) + return; + + if (exceptViewModel != null) + { + if (!threadListView.SelectedItems.Contains(exceptViewModel)) + { + if (!preserveThreadExpanding) + { + c.IsThreadExpanded = false; + } + + threadListView.SelectedItems.Clear(); + } + } + else + { + if (!preserveThreadExpanding) + { + c.IsThreadExpanded = false; + } + + threadListView.SelectedItems.Clear(); + } + }); + } + + /// + /// Recursively selects all mails, including thread items. + /// + public void SelectAllWino() + { + SelectAll(); + + Items.Where(a => a is ThreadMailItemViewModel).Cast().ForEach(c => + { + c.IsThreadExpanded = true; + + var threadListView = GetThreadInternalListView(c); + + threadListView?.SelectAll(); + }); + } + + // SelectedItems changed. + private void SelectedItemsChanged(object sender, SelectionChangedEventArgs e) + { + if (e.RemovedItems != null) + { + foreach (var removedItem in e.RemovedItems) + { + if (removedItem is MailItemViewModel removedMailItemViewModel) + { + // Mail item un-selected. + + removedMailItemViewModel.IsSelected = false; + WeakReferenceMessenger.Default.Send(new MailItemSelectionRemovedEvent(removedMailItemViewModel)); + } + } + } + + if (e.AddedItems != null) + { + foreach (var addedItem in e.AddedItems) + { + if (addedItem is MailItemViewModel addedMailItemViewModel) + { + // Mail item selected. + + addedMailItemViewModel.IsSelected = true; + + WeakReferenceMessenger.Default.Send(new MailItemSelectedEvent(addedMailItemViewModel)); + } + else if (addedItem is ThreadMailItemViewModel threadMailItemViewModel) + { + threadMailItemViewModel.IsThreadExpanded = true; + + // Don't select thread containers. + SelectedItems.Remove(addedItem); + } + } + } + + if (!IsThreadListView) + { + if (SelectionMode == ListViewSelectionMode.Extended && SelectedItems.Count == 1) + { + // Only 1 single item is selected in extended mode for main list view. + // We should un-select all thread items. + + Items.Where(a => a is ThreadMailItemViewModel).Cast().ForEach(c => + { + // c.IsThreadExpanded = false; + + var threadListView = GetThreadInternalListView(c); + + threadListView?.SelectedItems.Clear(); + }); + } + } + else + { + if (SelectionMode == ListViewSelectionMode.Extended && SelectedItems.Count == 1) + { + // Tell main list view to unselect all his items. + + if (SelectedItems[0] is MailItemViewModel selectedMailItemViewModel) + { + WeakReferenceMessenger.Default.Send(new ResetSingleMailItemSelectionEvent(selectedMailItemViewModel)); + } + } + } + } + + private WinoListView GetThreadInternalListView(ThreadMailItemViewModel threadMailItemViewModel) + { + var itemContainer = ContainerFromItem(threadMailItemViewModel); + + if (itemContainer is ListViewItem listItem) + { + var expander = listItem.GetChildByName("ThreadExpander"); + + if (expander != null) + return expander.Content as WinoListView; + } + + return null; + } + + public void Dispose() + { + DragItemsCompleted -= ItemDragCompleted; + DragItemsStarting -= ItemDragStarting; + SelectionChanged -= SelectedItemsChanged; + ItemClick -= MailItemClicked; + ProcessKeyboardAccelerators -= ProcessDelKey; + + if (internalScrollviewer != null) + { + internalScrollviewer.ViewChanged -= InternalScrollVeiwerViewChanged; + } + } + } +} diff --git a/Wino.Mail.WinUI/Controls/ControlConstants.cs b/Wino.Mail.WinUI/Controls/ControlConstants.cs new file mode 100644 index 00000000..4353f2f6 --- /dev/null +++ b/Wino.Mail.WinUI/Controls/ControlConstants.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; + +namespace Wino.Controls +{ + public static class ControlConstants + { + public static Dictionary WinoIconFontDictionary = new Dictionary() + { + { WinoIconGlyph.None, "\u0020" }, + { WinoIconGlyph.Archive, "\uE066" }, + { WinoIconGlyph.UnArchive, "\uE06C" }, + { WinoIconGlyph.Reply, "\uF176" }, + { WinoIconGlyph.ReplyAll, "\uF17A" }, + { WinoIconGlyph.Sync, "\uE902" }, + { WinoIconGlyph.Send, "\uEA8E" }, + { WinoIconGlyph.LightEditor, "\uE1F6" }, + { WinoIconGlyph.Delete, "\uEEA6" }, + { WinoIconGlyph.DarkEditor, "\uEE44" }, + { WinoIconGlyph.Draft, "\uF3BE" }, + { WinoIconGlyph.Flag, "\uF40C" }, + { WinoIconGlyph.ClearFlag, "\uF40F" }, + { WinoIconGlyph.Folder, "\uE643" }, + { WinoIconGlyph.Forward, "\uE7AA" }, + { WinoIconGlyph.Inbox, "\uF516" }, + { WinoIconGlyph.MarkRead, "\uF522" }, + { WinoIconGlyph.MarkUnread, "\uF529" }, + { WinoIconGlyph.MultiSelect, "\uE84D" }, + { WinoIconGlyph.Save, "\uEA43" }, + { WinoIconGlyph.CreateFolder, "\uE645" }, + { WinoIconGlyph.Pin, "\uF5FF" }, + { WinoIconGlyph.UnPin, "\uE985" }, + { WinoIconGlyph.Star, "\uF70D" }, + { WinoIconGlyph.Ignore, "\uF5D0" }, + { WinoIconGlyph.Junk, "\uE903" }, + { WinoIconGlyph.Find, "\uEA7D" }, + { WinoIconGlyph.Zoom, "\uEE8E" }, + { WinoIconGlyph.SpecialFolderInbox, "\uF516" }, + { WinoIconGlyph.SpecialFolderStarred, "\uF70D" }, + { WinoIconGlyph.SpecialFolderImportant, "\uE2F4" }, + { WinoIconGlyph.SpecialFolderSent, "\uEA8E" }, + { WinoIconGlyph.SpecialFolderDraft, "\uF3BE" }, + { WinoIconGlyph.SpecialFolderArchive, "\uE066" }, + { WinoIconGlyph.SpecialFolderDeleted, "\uEEA6" }, + { WinoIconGlyph.SpecialFolderJunk, "\uE903" }, + { WinoIconGlyph.SpecialFolderChat, "\uE2E3" }, + { WinoIconGlyph.SpecialFolderCategory, "\uF599" }, + { WinoIconGlyph.SpecialFolderUnread, "\uF529" }, + { WinoIconGlyph.SpecialFolderForums, "\uF5B8" }, + { WinoIconGlyph.SpecialFolderUpdated, "\uF565" }, + { WinoIconGlyph.SpecialFolderPersonal, "\uE25A" }, + { WinoIconGlyph.SpecialFolderPromotions, "\uF7B6" }, + { WinoIconGlyph.SpecialFolderSocial, "\uEEEB" }, + { WinoIconGlyph.SpecialFolderOther, "\uE643" }, + { WinoIconGlyph.SpecialFolderMore, "\uF0F4" }, + { WinoIconGlyph.Microsoft, "\uE900" }, + { WinoIconGlyph.Google, "\uE901" }, + { WinoIconGlyph.NewMail, "\uF107" }, + { WinoIconGlyph.TurnOfNotifications, "\uF11D" }, + { WinoIconGlyph.Rename, "\uF668" }, + { WinoIconGlyph.EmptyFolder, "\uE47E" }, + { WinoIconGlyph.DontSync, "\uF195" }, + { WinoIconGlyph.Move, "\uE7B8" }, + { WinoIconGlyph.Mail, "\uF509" }, + { WinoIconGlyph.More, "\uE824" }, + { WinoIconGlyph.CustomServer, "\uF509" }, + }; + } +} diff --git a/Wino.Mail.WinUI/Controls/ImagePreviewControl.cs b/Wino.Mail.WinUI/Controls/ImagePreviewControl.cs new file mode 100644 index 00000000..966b984a --- /dev/null +++ b/Wino.Mail.WinUI/Controls/ImagePreviewControl.cs @@ -0,0 +1,155 @@ +using System; +using System.Text.RegularExpressions; +using Fernandezja.ColorHashSharp; +using Windows.UI; + +using Wino.Core.Services; + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Media; +using Microsoft.UI.Xaml.Media.Imaging; +using Microsoft.UI.Xaml.Shapes; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Media.Imaging; +using Windows.UI.Xaml.Shapes; +#endif + +namespace Wino.Controls +{ + public class ImagePreviewControl : Control + { + private const string PART_EllipseInitialsGrid = "EllipseInitialsGrid"; + private const string PART_InitialsTextBlock = "InitialsTextBlock"; + private const string PART_KnownHostImage = "KnownHostImage"; + private const string PART_Ellipse = "Ellipse"; + + #region Dependency Properties + + public static readonly DependencyProperty FromNameProperty = DependencyProperty.Register(nameof(FromName), typeof(string), typeof(ImagePreviewControl), new PropertyMetadata(string.Empty, OnAddressInformationChanged)); + public static readonly DependencyProperty FromAddressProperty = DependencyProperty.Register(nameof(FromAddress), typeof(string), typeof(ImagePreviewControl), new PropertyMetadata(string.Empty, OnAddressInformationChanged)); + public static readonly DependencyProperty IsKnownProperty = DependencyProperty.Register(nameof(IsKnown), typeof(bool), typeof(ImagePreviewControl), new PropertyMetadata(false)); + + public string FromName + { + get { return (string)GetValue(FromNameProperty); } + set { SetValue(FromNameProperty, value); } + } + + public string FromAddress + { + get { return (string)GetValue(FromAddressProperty); } + set { SetValue(FromAddressProperty, value); } + } + + public bool IsKnown + { + get { return (bool)GetValue(IsKnownProperty); } + set { SetValue(IsKnownProperty, value); } + } + + + + #endregion + + private Ellipse Ellipse; + private Grid InitialsGrid; + private TextBlock InitialsTextblock; + private Image KnownHostImage; + + public ImagePreviewControl() + { + DefaultStyleKey = nameof(ImagePreviewControl); + } + + protected override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + InitialsGrid = GetTemplateChild(PART_EllipseInitialsGrid) as Grid; + InitialsTextblock = GetTemplateChild(PART_InitialsTextBlock) as TextBlock; + KnownHostImage = GetTemplateChild(PART_KnownHostImage) as Image; + Ellipse = GetTemplateChild(PART_Ellipse) as Ellipse; + + UpdateInformation(); + } + + private static void OnAddressInformationChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) + { + if (obj is ImagePreviewControl control) + control.UpdateInformation(); + } + + private void UpdateInformation() + { + if (KnownHostImage == null || InitialsGrid == null || InitialsTextblock == null || (string.IsNullOrEmpty(FromName) && string.IsNullOrEmpty(FromAddress))) + return; + + var host = ThumbnailService.GetHost(FromAddress); + + if (!string.IsNullOrEmpty(host)) + { + var tuple = ThumbnailService.CheckIsKnown(host); + + IsKnown = tuple.Item1; + host = tuple.Item2; + } + + if (IsKnown) + { + // Unrealize others. + + KnownHostImage.Visibility = Visibility.Visible; + InitialsGrid.Visibility = Visibility.Collapsed; + + // Apply company logo. + KnownHostImage.Source = new BitmapImage(new Uri(ThumbnailService.GetKnownHostImage(host))); + } + else + { + KnownHostImage.Visibility = Visibility.Collapsed; + InitialsGrid.Visibility = Visibility.Visible; + + var colorHash = new ColorHash(); + var rgb = colorHash.Rgb(FromAddress); + + Ellipse.Fill = new SolidColorBrush(Color.FromArgb(rgb.A, rgb.R, rgb.G, rgb.B)); + + InitialsTextblock.Text = ExtractInitialsFromName(FromName); + } + } + + public string ExtractInitialsFromName(string name) + { + // Change from name to from address in case of name doesn't exists. + if (string.IsNullOrEmpty(name)) + { + name = FromAddress; + } + + // first remove all: punctuation, separator chars, control chars, and numbers (unicode style regexes) + string initials = Regex.Replace(name, @"[\p{P}\p{S}\p{C}\p{N}]+", ""); + + // Replacing all possible whitespace/separator characters (unicode style), with a single, regular ascii space. + initials = Regex.Replace(initials, @"\p{Z}+", " "); + + // Remove all Sr, Jr, I, II, III, IV, V, VI, VII, VIII, IX at the end of names + initials = Regex.Replace(initials.Trim(), @"\s+(?:[JS]R|I{1,3}|I[VX]|VI{0,3})$", "", RegexOptions.IgnoreCase); + + // Extract up to 2 initials from the remaining cleaned name. + initials = Regex.Replace(initials, @"^(\p{L})[^\s]*(?:\s+(?:\p{L}+\s+(?=\p{L}))?(?:(\p{L})\p{L}*)?)?$", "$1$2").Trim(); + + if (initials.Length > 2) + { + // Worst case scenario, everything failed, just grab the first two letters of what we have left. + initials = initials.Substring(0, 2); + } + + return initials.ToUpperInvariant(); + } + } +} diff --git a/Wino.Mail.WinUI/Controls/MailItemDisplayInformationControl.xaml b/Wino.Mail.WinUI/Controls/MailItemDisplayInformationControl.xaml new file mode 100644 index 00000000..2e0e45b5 --- /dev/null +++ b/Wino.Mail.WinUI/Controls/MailItemDisplayInformationControl.xaml @@ -0,0 +1,276 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wino.Mail.WinUI/Controls/MailItemDisplayInformationControl.xaml.cs b/Wino.Mail.WinUI/Controls/MailItemDisplayInformationControl.xaml.cs new file mode 100644 index 00000000..f6f65652 --- /dev/null +++ b/Wino.Mail.WinUI/Controls/MailItemDisplayInformationControl.xaml.cs @@ -0,0 +1,287 @@ +using System; +using System.ComponentModel; +using System.Numerics; +using System.Windows.Input; +using Microsoft.UI.Xaml.Controls; + +using Wino.Core.Domain.Enums; +using Wino.Core.Domain.Models.MailItem; +using Wino.Extensions; +using Wino.Mail.ViewModels.Data; +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Input; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Input; +#endif +namespace Wino.Controls +{ + public sealed partial class MailItemDisplayInformationControl : UserControl, INotifyPropertyChanged + { + public ImagePreviewControl GetImagePreviewControl() => ContactImage; + + public static readonly DependencyProperty DisplayModeProperty = DependencyProperty.Register(nameof(DisplayMode), typeof(MailListDisplayMode), typeof(MailItemDisplayInformationControl), new PropertyMetadata(MailListDisplayMode.Spacious)); + public static readonly DependencyProperty ShowPreviewTextProperty = DependencyProperty.Register(nameof(ShowPreviewText), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(true)); + public static readonly DependencyProperty SnippetProperty = DependencyProperty.Register(nameof(Snippet), typeof(string), typeof(MailItemDisplayInformationControl), new PropertyMetadata(string.Empty)); + public static readonly DependencyProperty FromNameProperty = DependencyProperty.Register(nameof(FromName), typeof(string), typeof(MailItemDisplayInformationControl), new PropertyMetadata(string.Empty)); + public static readonly DependencyProperty SubjectProperty = DependencyProperty.Register(nameof(Subject), typeof(string), typeof(MailItemDisplayInformationControl), new PropertyMetadata("(no-subject)")); + public static readonly DependencyProperty IsReadProperty = DependencyProperty.Register(nameof(IsRead), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false)); + public static readonly DependencyProperty IsFlaggedProperty = DependencyProperty.Register(nameof(IsFlagged), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false)); + public static readonly DependencyProperty FromAddressProperty = DependencyProperty.Register(nameof(FromAddress), typeof(string), typeof(MailItemDisplayInformationControl), new PropertyMetadata(string.Empty)); + public static readonly DependencyProperty HasAttachmentsProperty = DependencyProperty.Register(nameof(HasAttachments), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false)); + public static readonly DependencyProperty IsCustomFocusedProperty = DependencyProperty.Register(nameof(IsCustomFocused), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false)); + public static readonly DependencyProperty ReceivedDateProperty = DependencyProperty.Register(nameof(ReceivedDate), typeof(DateTime), typeof(MailItemDisplayInformationControl), new PropertyMetadata(default(DateTime))); + public static readonly DependencyProperty IsDraftProperty = DependencyProperty.Register(nameof(IsDraft), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false)); + public static readonly DependencyProperty IsAvatarVisibleProperty = DependencyProperty.Register(nameof(IsAvatarVisible), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(true)); + public static readonly DependencyProperty IsSubjectVisibleProperty = DependencyProperty.Register(nameof(IsSubjectVisible), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(true)); + public static readonly DependencyProperty ConnectedExpanderProperty = DependencyProperty.Register(nameof(ConnectedExpander), typeof(Expander), typeof(MailItemDisplayInformationControl), new PropertyMetadata(null)); + public static readonly DependencyProperty LeftHoverActionProperty = DependencyProperty.Register(nameof(LeftHoverAction), typeof(MailOperation), typeof(MailItemDisplayInformationControl), new PropertyMetadata(MailOperation.None)); + public static readonly DependencyProperty CenterHoverActionProperty = DependencyProperty.Register(nameof(CenterHoverAction), typeof(MailOperation), typeof(MailItemDisplayInformationControl), new PropertyMetadata(MailOperation.None)); + public static readonly DependencyProperty RightHoverActionProperty = DependencyProperty.Register(nameof(RightHoverAction), typeof(MailOperation), typeof(MailItemDisplayInformationControl), new PropertyMetadata(MailOperation.None)); + public static readonly DependencyProperty HoverActionExecutedCommandProperty = DependencyProperty.Register(nameof(HoverActionExecutedCommand), typeof(ICommand), typeof(MailItemDisplayInformationControl), new PropertyMetadata(null)); + public static readonly DependencyProperty MailItemProperty = DependencyProperty.Register(nameof(MailItem), typeof(IMailItem), typeof(MailItemDisplayInformationControl), new PropertyMetadata(null)); + public static readonly DependencyProperty IsHoverActionsEnabledProperty = DependencyProperty.Register(nameof(IsHoverActionsEnabled), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(true)); + public static readonly DependencyProperty Prefer24HourTimeFormatProperty = DependencyProperty.Register(nameof(Prefer24HourTimeFormat), typeof(bool), typeof(MailItemDisplayInformationControl), new PropertyMetadata(false)); + + public bool Prefer24HourTimeFormat + { + get { return (bool)GetValue(Prefer24HourTimeFormatProperty); } + set { SetValue(Prefer24HourTimeFormatProperty, value); } + } + + public bool IsHoverActionsEnabled + { + get { return (bool)GetValue(IsHoverActionsEnabledProperty); } + set { SetValue(IsHoverActionsEnabledProperty, value); } + } + + public IMailItem MailItem + { + get { return (IMailItem)GetValue(MailItemProperty); } + set { SetValue(MailItemProperty, value); } + } + + public ICommand HoverActionExecutedCommand + { + get { return (ICommand)GetValue(HoverActionExecutedCommandProperty); } + set { SetValue(HoverActionExecutedCommandProperty, value); } + } + + public MailOperation LeftHoverAction + { + get { return (MailOperation)GetValue(LeftHoverActionProperty); } + set { SetValue(LeftHoverActionProperty, value); } + } + + public MailOperation CenterHoverAction + { + get { return (MailOperation)GetValue(CenterHoverActionProperty); } + set { SetValue(CenterHoverActionProperty, value); } + } + + public MailOperation RightHoverAction + { + get { return (MailOperation)GetValue(RightHoverActionProperty); } + set { SetValue(RightHoverActionProperty, value); } + } + + + public event PropertyChangedEventHandler PropertyChanged; + + public Expander ConnectedExpander + { + get { return (Expander)GetValue(ConnectedExpanderProperty); } + set { SetValue(ConnectedExpanderProperty, value); } + } + + public bool IsSubjectVisible + { + get { return (bool)GetValue(IsSubjectVisibleProperty); } + set { SetValue(IsSubjectVisibleProperty, value); } + } + + public bool IsAvatarVisible + { + get { return (bool)GetValue(IsAvatarVisibleProperty); } + set { SetValue(IsAvatarVisibleProperty, value); } + } + + public bool IsDraft + { + get { return (bool)GetValue(IsDraftProperty); } + set { SetValue(IsDraftProperty, value); } + } + + public DateTime ReceivedDate + { + get { return (DateTime)GetValue(ReceivedDateProperty); } + set { SetValue(ReceivedDateProperty, value); } + } + public bool IsCustomFocused + { + get { return (bool)GetValue(IsCustomFocusedProperty); } + set { SetValue(IsCustomFocusedProperty, value); } + } + + public bool HasAttachments + { + get { return (bool)GetValue(HasAttachmentsProperty); } + set { SetValue(HasAttachmentsProperty, value); } + } + + public bool IsRead + { + get { return (bool)GetValue(IsReadProperty); } + set { SetValue(IsReadProperty, value); } + } + + public bool IsFlagged + { + get { return (bool)GetValue(IsFlaggedProperty); } + set { SetValue(IsFlaggedProperty, value); } + } + + public string FromAddress + { + get { return (string)GetValue(FromAddressProperty); } + set + { + SetValue(FromAddressProperty, value); + + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(DisplayName))); + } + } + + public string DisplayName + { + get + { + if (string.IsNullOrEmpty(FromName)) + return FromAddress; + + return FromName; + } + } + public string FromName + { + get => (string)GetValue(FromNameProperty); + set + { + SetValue(FromNameProperty, value); + + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(DisplayName))); + } + } + + public string Subject + { + get { return (string)GetValue(SubjectProperty); } + set { SetValue(SubjectProperty, value); } + } + + public string Snippet + { + get { return (string)GetValue(SnippetProperty); } + set { SetValue(SnippetProperty, value); } + } + + public bool ShowPreviewText + { + get { return (bool)GetValue(ShowPreviewTextProperty); } + set { SetValue(ShowPreviewTextProperty, value); } + } + + public MailListDisplayMode DisplayMode + { + get { return (MailListDisplayMode)GetValue(DisplayModeProperty); } + set { SetValue(DisplayModeProperty, value); } + } + + private bool tappedHandlingFlag = false; + + public MailItemDisplayInformationControl() + { + this.InitializeComponent(); + + var compositor = this.Visual().Compositor; + + var leftBackgroundVisual = compositor.CreateSpriteVisual(); + RootContainerVisualWrapper.SetChildVisual(leftBackgroundVisual); + MainContentContainer.EnableImplicitAnimation(VisualPropertyType.Offset, 400); + + RootContainer.EnableImplicitAnimation(VisualPropertyType.Offset, 400); + ContentGrid.EnableImplicitAnimation(VisualPropertyType.Offset, 400); + ContentStackpanel.EnableImplicitAnimation(VisualPropertyType.Offset, 400); + IconsContainer.EnableImplicitAnimation(VisualPropertyType.Offset, 400); + + RootContainerVisualWrapper.SizeChanged += (s, e) => leftBackgroundVisual.Size = e.NewSize.ToVector2(); + } + + private void ControlPointerEntered(object sender, PointerRoutedEventArgs e) + { + if (IsHoverActionsEnabled) + { + HoverActionButtons.Visibility = Visibility.Visible; + } + } + + private void ControlPointerExited(object sender, PointerRoutedEventArgs e) + { + if (IsHoverActionsEnabled) + { + HoverActionButtons.Visibility = Visibility.Collapsed; + } + } + + private void ExecuteHoverAction(MailOperation operation) + { + MailOperationPreperationRequest package = null; + + if (MailItem is MailItemViewModel mailItemViewModel) + package = new MailOperationPreperationRequest(operation, mailItemViewModel.MailCopy, toggleExecution: true); + else if (MailItem is ThreadMailItemViewModel threadMailItemViewModel) + package = new MailOperationPreperationRequest(operation, threadMailItemViewModel.GetMailCopies(), toggleExecution: true); + + if (package == null) return; + + tappedHandlingFlag = true; + + HoverActionExecutedCommand?.Execute(package); + } + + private void ThreadHeaderTapped(object sender, TappedRoutedEventArgs e) + { + // Due to CanDrag=True, outer expander doesn't get the click event and it doesn't expand. We expand here manually. + // Also hover action button clicks will be delegated here after the execution runs. + // We should not expand the thread if the reason we are here is for hover actions. + + if (tappedHandlingFlag) + { + tappedHandlingFlag = false; + e.Handled = true; + return; + } + + if (ConnectedExpander == null) return; + + ConnectedExpander.IsExpanded = !ConnectedExpander.IsExpanded; + } + + private void FirstActionClicked(object sender, RoutedEventArgs e) + { + ExecuteHoverAction(LeftHoverAction); + } + + private void SecondActionClicked(object sender, RoutedEventArgs e) + { + ExecuteHoverAction(CenterHoverAction); + } + + private void ThirdActionClicked(object sender, RoutedEventArgs e) + { + ExecuteHoverAction(RightHoverAction); + } + } +} diff --git a/Wino.Mail.WinUI/Controls/RendererCommandBar.cs b/Wino.Mail.WinUI/Controls/RendererCommandBar.cs new file mode 100644 index 00000000..6bf58e71 --- /dev/null +++ b/Wino.Mail.WinUI/Controls/RendererCommandBar.cs @@ -0,0 +1,141 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Windows.Input; + +using Wino.Core.Domain.Enums; +using Wino.Core.Domain.Models.Menus; +using Wino.Helpers; +using Wino.MenuFlyouts; +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +#endif +namespace Wino.Controls +{ + public class RendererCommandBar : CommandBar, IDisposable + { + public static readonly DependencyProperty MenuItemsProperty = DependencyProperty.Register(nameof(MenuItemsProperty), typeof(ObservableCollection), typeof(RendererCommandBar), new PropertyMetadata(null, OnMenuItemsChanged)); + public static readonly DependencyProperty OperationClickedCommandProperty = DependencyProperty.Register(nameof(OperationClickedCommand), typeof(ICommand), typeof(RendererCommandBar), new PropertyMetadata(null)); + + public ICommand OperationClickedCommand + { + get { return (ICommand)GetValue(OperationClickedCommandProperty); } + set { SetValue(OperationClickedCommandProperty, value); } + } + + public ObservableCollection MenuItems + { + get { return (ObservableCollection)GetValue(MenuItemsProperty); } + set { SetValue(MenuItemsProperty, value); } + } + + public RendererCommandBar() + { + this.DefaultStyleKey = typeof(CommandBar); + } + + private static void OnMenuItemsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) + { + if (obj is RendererCommandBar commandBar) + { + if (args.OldValue != null) + commandBar.UnregisterButtonCollection(args.NewValue as ObservableCollection); + + if (args.NewValue != null) + commandBar.RegisterButtonCollection(args.NewValue as ObservableCollection); + } + } + + private void RegisterButtonCollection(ObservableCollection collection) + { + collection.CollectionChanged -= ButtonCollectionChanged; + collection.CollectionChanged += ButtonCollectionChanged; + + InitItems(collection); + } + + private void UnregisterButtonCollection(ObservableCollection collection) + { + collection.CollectionChanged -= ButtonCollectionChanged; + } + + // One time initializer on registration. + private void InitItems(IEnumerable items) + { + foreach (var item in items) + { + var operationText = XamlHelpers.GetOperationString(item.Operation); + + var operationAppBarItem = new AppBarButton() + { + Label = operationText + }; + + ToolTipService.SetToolTip(operationAppBarItem, operationText); + + PrimaryCommands.Add(operationAppBarItem); + } + } + + private void ButtonCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Reset) + { + PrimaryCommands.Clear(); + SecondaryCommands.Clear(); + } + + if (e.NewItems != null) + { + foreach (var newItem in e.NewItems) + { + if (newItem is MailOperationMenuItem item) + { + var button = new RendererCommandBarItem(item.Operation, Clicked) + { + IsEnabled = item.IsEnabled + }; + + if (!item.IsSecondaryMenuPreferred) + PrimaryCommands.Add(button); + else + SecondaryCommands.Add(button); + } + } + } + } + + private void Clicked(MailOperation operation) + { + OperationClickedCommand?.Execute(operation); + } + + private void DisposeMenuItems() + { + foreach (var item in this.PrimaryCommands) + { + if (item is RendererCommandBarItem rendererCommandBarItem) + { + rendererCommandBarItem.Dispose(); + } + } + + foreach (var item in this.SecondaryCommands) + { + if (item is RendererCommandBarItem rendererCommandBarItem) + { + rendererCommandBarItem.Dispose(); + } + } + } + + public void Dispose() + { + DisposeMenuItems(); + } + } +} diff --git a/Wino.Mail.WinUI/Controls/SettingsMenuItemControl.cs b/Wino.Mail.WinUI/Controls/SettingsMenuItemControl.cs new file mode 100644 index 00000000..3f5ee019 --- /dev/null +++ b/Wino.Mail.WinUI/Controls/SettingsMenuItemControl.cs @@ -0,0 +1,77 @@ +using System.Windows.Input; + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +#endif +namespace Wino.Controls +{ + /// + /// Templated button for each setting in Settings Dialog. + /// + public class SettingsMenuItemControl : Control + { + public string Title + { + get { return (string)GetValue(TitleProperty); } + set { SetValue(TitleProperty, value); } + } + + public string Description + { + get { return (string)GetValue(DescriptionProperty); } + set { SetValue(DescriptionProperty, value); } + } + + public FrameworkElement Icon + { + get { return (FrameworkElement)GetValue(IconProperty); } + set { SetValue(IconProperty, value); } + } + + + public ICommand Command + { + get { return (ICommand)GetValue(CommandProperty); } + set { SetValue(CommandProperty, value); } + } + + + + public object CommandParameter + { + get { return (object)GetValue(CommandParameterProperty); } + set { SetValue(CommandParameterProperty, value); } + } + + public bool IsClickable + { + get { return (bool)GetValue(IsClickableProperty); } + set { SetValue(IsClickableProperty, value); } + } + + public bool IsNavigateIconVisible + { + get { return (bool)GetValue(IsNavigateIconVisibleProperty); } + set { SetValue(IsNavigateIconVisibleProperty, value); } + } + + public FrameworkElement SideContent + { + get { return (FrameworkElement)GetValue(SideContentProperty); } + set { SetValue(SideContentProperty, value); } + } + + public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register(nameof(CommandParameter), typeof(object), typeof(SettingsMenuItemControl), new PropertyMetadata(null)); + public static readonly DependencyProperty SideContentProperty = DependencyProperty.Register(nameof(SideContent), typeof(FrameworkElement), typeof(SettingsMenuItemControl), new PropertyMetadata(null)); + public static readonly DependencyProperty IsClickableProperty = DependencyProperty.Register(nameof(IsClickable), typeof(bool), typeof(SettingsMenuItemControl), new PropertyMetadata(true)); + public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(nameof(Command), typeof(ICommand), typeof(SettingsMenuItemControl), new PropertyMetadata(null)); + public static readonly DependencyProperty IconProperty = DependencyProperty.Register(nameof(Icon), typeof(FrameworkElement), typeof(SettingsMenuItemControl), new PropertyMetadata(null)); + public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register(nameof(Description), typeof(string), typeof(SettingsMenuItemControl), new PropertyMetadata(string.Empty)); + public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(nameof(Title), typeof(string), typeof(SettingsMenuItemControl), new PropertyMetadata(string.Empty)); + public static readonly DependencyProperty IsNavigateIconVisibleProperty = DependencyProperty.Register(nameof(IsNavigateIconVisible), typeof(bool), typeof(SettingsMenuItemControl), new PropertyMetadata(true)); + } +} diff --git a/Wino.Mail.WinUI/Controls/WinoFontIcon.cs b/Wino.Mail.WinUI/Controls/WinoFontIcon.cs new file mode 100644 index 00000000..f5d411d3 --- /dev/null +++ b/Wino.Mail.WinUI/Controls/WinoFontIcon.cs @@ -0,0 +1,104 @@ + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Media; +#else +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Media; +#endif + +namespace Wino.Controls +{ + public enum WinoIconGlyph + { + None, + NewMail, + Google, + Microsoft, + CustomServer, + Archive, + UnArchive, + Reply, + ReplyAll, + LightEditor, + DarkEditor, + Delete, + Move, + Mail, + Draft, + Flag, + ClearFlag, + Folder, + Forward, + Inbox, + MarkRead, + MarkUnread, + Send, + Save, + Sync, + MultiSelect, + Zoom, + Pin, + UnPin, + Ignore, + Star, + CreateFolder, + Junk, + More, + Find, + SpecialFolderInbox, + SpecialFolderStarred, + SpecialFolderImportant, + SpecialFolderSent, + SpecialFolderDraft, + SpecialFolderArchive, + SpecialFolderDeleted, + SpecialFolderJunk, + SpecialFolderChat, + SpecialFolderCategory, + SpecialFolderUnread, + SpecialFolderForums, + SpecialFolderUpdated, + SpecialFolderPersonal, + SpecialFolderPromotions, + SpecialFolderSocial, + SpecialFolderOther, + SpecialFolderMore, + TurnOfNotifications, + EmptyFolder, + Rename, + DontSync + } + + public class WinoFontIcon : FontIcon + { + public WinoIconGlyph Icon + { + get { return (WinoIconGlyph)GetValue(IconProperty); } + set { SetValue(IconProperty, value); } + } + + public static readonly DependencyProperty IconProperty = DependencyProperty.Register(nameof(Icon), typeof(WinoIconGlyph), typeof(WinoFontIcon), new PropertyMetadata(WinoIconGlyph.Flag, OnIconChanged)); + + public WinoFontIcon() + { + FontFamily = new FontFamily("ms-appx:///Assets/WinoIcons.ttf#WinoIcons"); + FontSize = 32; + } + + private static void OnIconChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) + { + if (obj is WinoFontIcon fontIcon) + { + fontIcon.UpdateGlyph(); + } + } + + private void UpdateGlyph() + { + Glyph = ControlConstants.WinoIconFontDictionary[Icon]; + } + } +} diff --git a/Wino.Mail.WinUI/Controls/WinoFontIconSource.cs b/Wino.Mail.WinUI/Controls/WinoFontIconSource.cs new file mode 100644 index 00000000..907d5c9f --- /dev/null +++ b/Wino.Mail.WinUI/Controls/WinoFontIconSource.cs @@ -0,0 +1,41 @@ + + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Media; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Media; +#endif +namespace Wino.Controls +{ + public class WinoFontIconSource : Microsoft.UI.Xaml.Controls.FontIconSource + { + public WinoIconGlyph Icon + { + get { return (WinoIconGlyph)GetValue(IconProperty); } + set { SetValue(IconProperty, value); } + } + + public static readonly DependencyProperty IconProperty = DependencyProperty.Register(nameof(Icon), typeof(WinoIconGlyph), typeof(WinoFontIconSource), new PropertyMetadata(WinoIconGlyph.Flag, OnIconChanged)); + + public WinoFontIconSource() + { + FontFamily = new FontFamily("ms-appx:///Assets/WinoIcons.ttf#WinoIcons"); + FontSize = 32; + } + + private static void OnIconChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) + { + if (obj is WinoFontIconSource fontIcon) + { + fontIcon.UpdateGlyph(); + } + } + + private void UpdateGlyph() + { + Glyph = ControlConstants.WinoIconFontDictionary[Icon]; + } + } +} diff --git a/Wino.Mail.WinUI/Controls/WinoInfoBar.cs b/Wino.Mail.WinUI/Controls/WinoInfoBar.cs new file mode 100644 index 00000000..fe62d30b --- /dev/null +++ b/Wino.Mail.WinUI/Controls/WinoInfoBar.cs @@ -0,0 +1,97 @@ +using System; +using System.Numerics; + +using Microsoft.UI.Xaml.Controls; + +using Wino.Core.Domain.Enums; +using CommunityToolkit.WinUI.Animations; + +#if NET8_0 +using Microsoft.UI.Xaml; +#else +using Windows.UI.Xaml; +#endif +namespace Wino.Controls +{ + public class WinoInfoBar : InfoBar + { + public static readonly DependencyProperty AnimationTypeProperty = DependencyProperty.Register(nameof(AnimationType), typeof(InfoBarAnimationType), typeof(WinoInfoBar), new PropertyMetadata(InfoBarAnimationType.SlideFromRightToLeft)); + public static readonly DependencyProperty DismissIntervalProperty = DependencyProperty.Register(nameof(DismissInterval), typeof(int), typeof(WinoInfoBar), new PropertyMetadata(5, new PropertyChangedCallback(OnDismissIntervalChanged))); + + public InfoBarAnimationType AnimationType + { + get { return (InfoBarAnimationType)GetValue(AnimationTypeProperty); } + set { SetValue(AnimationTypeProperty, value); } + } + + public int DismissInterval + { + get { return (int)GetValue(DismissIntervalProperty); } + set { SetValue(DismissIntervalProperty, value); } + } + + private readonly DispatcherTimer _dispatcherTimer = new DispatcherTimer(); + + public WinoInfoBar() + { + RegisterPropertyChangedCallback(IsOpenProperty, IsOpenChanged); + + _dispatcherTimer.Interval = TimeSpan.FromSeconds(DismissInterval); + } + + private static void OnDismissIntervalChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) + { + if (obj is WinoInfoBar bar) + { + bar.UpdateInterval(bar.DismissInterval); + } + } + + private void UpdateInterval(int seconds) => _dispatcherTimer.Interval = TimeSpan.FromSeconds(seconds); + + private async void IsOpenChanged(DependencyObject sender, DependencyProperty dp) + { + if (sender is WinoInfoBar control) + { + // Message shown. + if (!control.IsOpen) return; + + Opacity = 1; + + _dispatcherTimer.Stop(); + + _dispatcherTimer.Tick -= TimerTick; + _dispatcherTimer.Tick += TimerTick; + + _dispatcherTimer.Start(); + + // Slide from right. + if (AnimationType == InfoBarAnimationType.SlideFromRightToLeft) + { + await AnimationBuilder.Create().Translation(new Vector3(0, 0, 0), new Vector3(150, 0, 0), null, TimeSpan.FromSeconds(0.5)).StartAsync(this); + } + else if (AnimationType == InfoBarAnimationType.SlideFromBottomToTop) + { + await AnimationBuilder.Create().Translation(new Vector3(0, 0, 0), new Vector3(0, 50, 0), null, TimeSpan.FromSeconds(0.5)).StartAsync(this); + } + } + } + + private async void TimerTick(object sender, object e) + { + _dispatcherTimer.Stop(); + _dispatcherTimer.Tick -= TimerTick; + + if (AnimationType == InfoBarAnimationType.SlideFromRightToLeft) + { + await AnimationBuilder.Create().Translation(new Vector3((float)ActualWidth, 0, 0), new Vector3(0, 0, 0), null, TimeSpan.FromSeconds(0.5)).StartAsync(this); + } + else if (AnimationType == InfoBarAnimationType.SlideFromBottomToTop) + { + await AnimationBuilder.Create().Translation(new Vector3(0, (float)ActualHeight, 0), new Vector3(0, 0, 0), null, TimeSpan.FromSeconds(0.5)).StartAsync(this); + } + + IsOpen = false; + } + } +} diff --git a/Wino.Mail.WinUI/Controls/WinoNavigationViewItem.cs b/Wino.Mail.WinUI/Controls/WinoNavigationViewItem.cs new file mode 100644 index 00000000..0a7b44fb --- /dev/null +++ b/Wino.Mail.WinUI/Controls/WinoNavigationViewItem.cs @@ -0,0 +1,52 @@ +using System.Numerics; +using Microsoft.UI.Xaml.Controls; + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Hosting; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Hosting; +#endif +namespace Wino.Controls +{ + public class WinoNavigationViewItem : NavigationViewItem + { + public bool IsDraggingItemOver + { + get { return (bool)GetValue(IsDraggingItemOverProperty); } + set { SetValue(IsDraggingItemOverProperty, value); } + } + + public static readonly DependencyProperty IsDraggingItemOverProperty = DependencyProperty.Register(nameof(IsDraggingItemOver), typeof(bool), typeof(WinoNavigationViewItem), new PropertyMetadata(false, OnIsDraggingItemOverChanged)); + + private static void OnIsDraggingItemOverChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) + { + if (obj is WinoNavigationViewItem control) + control.UpdateDragEnterState(); + } + + private void UpdateDragEnterState() + { + // TODO: Add animation. Maybe after overriding DragUI in shell? + + //if (IsDraggingItemOver) + //{ + // ScaleAnimation(new System.Numerics.Vector3(1.2f, 1.2f, 1.2f)); + //} + //else + //{ + // ScaleAnimation(new System.Numerics.Vector3(1f, 1f, 1f)); + //} + } + + private void ScaleAnimation(Vector3 vector) + { + if (this.Content is UIElement content) + { + var visual = ElementCompositionPreview.GetElementVisual(content); + visual.Scale = vector; + } + } + } +} diff --git a/Wino.Mail.WinUI/Controls/WinoPivotControl.xaml b/Wino.Mail.WinUI/Controls/WinoPivotControl.xaml new file mode 100644 index 00000000..a524e6d3 --- /dev/null +++ b/Wino.Mail.WinUI/Controls/WinoPivotControl.xaml @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wino.Mail.WinUI/Controls/WinoPivotControl.xaml.cs b/Wino.Mail.WinUI/Controls/WinoPivotControl.xaml.cs new file mode 100644 index 00000000..05df02ba --- /dev/null +++ b/Wino.Mail.WinUI/Controls/WinoPivotControl.xaml.cs @@ -0,0 +1,198 @@ +using System; +using System.Diagnostics; +using System.Numerics; +using System.Threading.Tasks; +using Windows.Foundation; + +using Wino.Extensions; +#if NET8_0 +using Microsoft.UI; +using Microsoft.UI.Composition; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Media; +#else +using Windows.UI; +using Windows.UI.Composition; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Controls.Primitives; +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml.Input; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Navigation; +#endif +namespace Wino.Controls +{ + // TODO: Memory leak with FolderPivot bindings. + public sealed partial class WinoPivotControl : UserControl + { + private Compositor _compositor; + private ShapeVisual _shapeVisual; + private CompositionSpriteShape _spriteShape; + private CompositionRoundedRectangleGeometry _roundedRectangle; + + public event EventHandler SelectionChanged; + + public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register(nameof(SelectedItem), typeof(object), typeof(WinoPivotControl), new PropertyMetadata(null)); + public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register(nameof(ItemsSource), typeof(object), typeof(WinoPivotControl), new PropertyMetadata(null)); + public static readonly DependencyProperty SelectorPipeColorProperty = DependencyProperty.Register(nameof(SelectorPipeColor), typeof(SolidColorBrush), typeof(WinoPivotControl), new PropertyMetadata(Colors.Transparent, OnSelectorPipeColorChanged)); + public static readonly DependencyProperty DataTemplateProperty = DependencyProperty.Register(nameof(DataTemplate), typeof(DataTemplate), typeof(WinoPivotControl), new PropertyMetadata(null)); + + public DataTemplate DataTemplate + { + get { return (DataTemplate)GetValue(DataTemplateProperty); } + set { SetValue(DataTemplateProperty, value); } + } + + public SolidColorBrush SelectorPipeColor + { + get { return (SolidColorBrush)GetValue(SelectorPipeColorProperty); } + set { SetValue(SelectorPipeColorProperty, value); } + } + + public object SelectedItem + { + get { return (object)GetValue(SelectedItemProperty); } + set { SetValue(SelectedItemProperty, value); } + } + + public object ItemsSource + { + get { return (object)GetValue(ItemsSourceProperty); } + set { SetValue(ItemsSourceProperty, value); } + } + + private static void OnSelectorPipeColorChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) + { + if (obj is WinoPivotControl control) + { + control.UpdateSelectorPipeColor(); + } + } + + private void UpdateSelectorPipeColor() + { + if (_spriteShape != null && _compositor != null) + { + _spriteShape.FillBrush = _compositor.CreateColorBrush(SelectorPipeColor.Color); + } + } + + private void CreateSelectorVisuals() + { + _compositor = this.Visual().Compositor; + + _roundedRectangle = _compositor.CreateRoundedRectangleGeometry(); + _roundedRectangle.CornerRadius = new Vector2(3, 3); + + _spriteShape = _compositor.CreateSpriteShape(_roundedRectangle); + _spriteShape.CenterPoint = new Vector2(100, 100); + + _shapeVisual = _compositor.CreateShapeVisual(); + + _shapeVisual.Shapes.Clear(); + _shapeVisual.Shapes.Add(_spriteShape); + + SelectorPipe.SetChildVisual(_shapeVisual); + + _shapeVisual.EnableImplicitAnimation(VisualPropertyType.Size, 400); + } + + public WinoPivotControl() + { + this.InitializeComponent(); + + CreateSelectorVisuals(); + } + + private bool IsContainerPresent() + { + return SelectedItem != null && PivotHeaders.ContainerFromItem(SelectedItem) != null; + } + + private void PivotHeaders_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + UpdateVisuals(); + + SelectionChanged?.Invoke(sender, e); + } + + private void UpdateVisuals() + { + MoveSelector(); + } + + private void UpdateSelectorVisibility() + { + SelectorPipe.Visibility = IsContainerPresent() ? Visibility.Visible : Visibility.Collapsed; + } + + private async void MoveSelector() + { + if (PivotHeaders.SelectedItem != null) + { + // Get selected item container position + // TODO: It's bad... + while (PivotHeaders.ContainerFromItem(PivotHeaders.SelectedItem) == null) + { + await Task.Delay(100); + } + + UpdateSelectorVisibility(); + + var container = PivotHeaders.ContainerFromItem(PivotHeaders.SelectedItem) as FrameworkElement; + + if (container != null) + { + var transformToVisual = container.TransformToVisual(this); + Point screenCoords = transformToVisual.TransformPoint(new Point(0, 0)); + + float actualWidth = 0, leftMargin = 0, translateX = 0; + + leftMargin = (float)(screenCoords.X); + + if (PivotHeaders.Items.Count > 1) + { + // Multiple items, pipe is centered. + + actualWidth = (float)(container.ActualWidth + 12) / 2; + translateX = leftMargin - 10 + (actualWidth / 2); + } + else + { + actualWidth = (float)(container.ActualWidth) - 12; + translateX = leftMargin + 4; + } + + SelectorPipe.Width = actualWidth; + SelectorPipe.Translation = new Vector3(translateX, 0, 0); + } + else + { + Debug.WriteLine("Container null"); + } + } + } + + private void SelectorPipeSizeChanged(object sender, SizeChangedEventArgs e) + { + _roundedRectangle.Size = e.NewSize.ToVector2(); + _shapeVisual.Size = e.NewSize.ToVector2(); + } + + private void ControlUnloaded(object sender, RoutedEventArgs e) + { + //PivotHeaders.SelectionChanged -= PivotHeaders_SelectionChanged; + //PivotHeaders.SelectedItem = null; + + //SelectedItem = null; + //ItemsSource = null; + } + + private void ControlLoaded(object sender, RoutedEventArgs e) + { + // Bindings.Update(); + } + } +} diff --git a/Wino.Mail.WinUI/Controls/WinoSwipeControlItems.cs b/Wino.Mail.WinUI/Controls/WinoSwipeControlItems.cs new file mode 100644 index 00000000..5f3256e3 --- /dev/null +++ b/Wino.Mail.WinUI/Controls/WinoSwipeControlItems.cs @@ -0,0 +1,87 @@ +using System.Linq; +using Microsoft.UI.Xaml.Controls; + +using Wino.Core.Domain.Enums; +using Wino.Core.Domain.Models.MailItem; +using Wino.Helpers; +using Wino.Mail.ViewModels.Data; + +#if NET8_0 +using Microsoft.UI.Xaml; +#else +using Windows.UI.Xaml; +#endif +namespace Wino.Controls +{ + public class WinoSwipeControlItems : SwipeItems + { + public static readonly DependencyProperty SwipeOperationProperty = DependencyProperty.Register(nameof(SwipeOperation), typeof(MailOperation), typeof(WinoSwipeControlItems), new PropertyMetadata(default(MailOperation), new PropertyChangedCallback(OnItemsChanged))); + public static readonly DependencyProperty MailItemProperty = DependencyProperty.Register(nameof(MailItem), typeof(IMailItem), typeof(WinoSwipeControlItems), new PropertyMetadata(null)); + + public IMailItem MailItem + { + get { return (IMailItem)GetValue(MailItemProperty); } + set { SetValue(MailItemProperty, value); } + } + + + public MailOperation SwipeOperation + { + get { return (MailOperation)GetValue(SwipeOperationProperty); } + set { SetValue(SwipeOperationProperty, value); } + } + + private static void OnItemsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) + { + if (obj is WinoSwipeControlItems control) + { + control.BuildSwipeItems(); + } + } + + private void BuildSwipeItems() + { + this.Clear(); + + var swipeItem = GetSwipeItem(SwipeOperation); + + this.Add(swipeItem); + } + + private SwipeItem GetSwipeItem(MailOperation operation) + { + if (MailItem == null) return null; + + var finalOperation = operation; + + bool isSingleItem = MailItem is MailItemViewModel; + + if (isSingleItem) + { + var singleItem = MailItem as MailItemViewModel; + + if (operation == MailOperation.MarkAsRead && singleItem.IsRead) + finalOperation = MailOperation.MarkAsUnread; + else if (operation == MailOperation.MarkAsUnread && !singleItem.IsRead) + finalOperation = MailOperation.MarkAsRead; + } + else + { + var threadItem = MailItem as ThreadMailItemViewModel; + + if (operation == MailOperation.MarkAsRead && threadItem.ThreadItems.All(a => a.IsRead)) + finalOperation = MailOperation.MarkAsUnread; + else if (operation == MailOperation.MarkAsUnread && threadItem.ThreadItems.All(a => !a.IsRead)) + finalOperation = MailOperation.MarkAsRead; + } + + var item = new SwipeItem() + { + IconSource = new WinoFontIconSource() { Icon = XamlHelpers.GetWinoIconGlyph(finalOperation) }, + Text = XamlHelpers.GetOperationString(finalOperation), + }; + + return item; + } + } +} diff --git a/Wino.Mail.WinUI/Converters/ReverseBooleanConverter.cs b/Wino.Mail.WinUI/Converters/ReverseBooleanConverter.cs new file mode 100644 index 00000000..3dd07334 --- /dev/null +++ b/Wino.Mail.WinUI/Converters/ReverseBooleanConverter.cs @@ -0,0 +1,27 @@ +using System; + + +#if NET8_0 +using Microsoft.UI.Xaml.Data; +#else +using Windows.UI.Xaml.Data; +#endif + +namespace Wino.Converters +{ + public class ReverseBooleanConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, string language) + { + if (value is bool boolval) + return !boolval; + + return false; + } + + public object ConvertBack(object value, Type targetType, object parameter, string language) + { + throw new NotImplementedException(); + } + } +} diff --git a/Wino.Mail.WinUI/Converters/ReverseBooleanToVisibilityConverter.cs b/Wino.Mail.WinUI/Converters/ReverseBooleanToVisibilityConverter.cs new file mode 100644 index 00000000..7ab054a9 --- /dev/null +++ b/Wino.Mail.WinUI/Converters/ReverseBooleanToVisibilityConverter.cs @@ -0,0 +1,26 @@ +using System; + + +#if NET8_0 +using Microsoft.UI.Xaml.Data; +using Microsoft.UI.Xaml; +#else +using Windows.UI.Xaml.Data; +using Windows.UI.Xaml; +#endif + +namespace Wino.Converters +{ + public class ReverseBooleanToVisibilityConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, string language) + { + return ((bool)value) ? Visibility.Collapsed : Visibility.Visible; + } + + public object ConvertBack(object value, Type targetType, object parameter, string language) + { + throw new NotImplementedException(); + } + } +} diff --git a/Wino.Mail.WinUI/Dialogs/AccountCreationDialog.xaml b/Wino.Mail.WinUI/Dialogs/AccountCreationDialog.xaml new file mode 100644 index 00000000..98cac4d6 --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/AccountCreationDialog.xaml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wino.Mail.WinUI/Dialogs/AccountCreationDialog.xaml.cs b/Wino.Mail.WinUI/Dialogs/AccountCreationDialog.xaml.cs new file mode 100644 index 00000000..d100a983 --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/AccountCreationDialog.xaml.cs @@ -0,0 +1,33 @@ +using Wino.Core.Domain.Enums; +using Wino.Helpers; + +namespace Wino.Dialogs +{ + public sealed partial class AccountCreationDialog : BaseAccountCreationDialog + { + public AccountCreationDialog() + { + InitializeComponent(); + } + + public override void UpdateState() + { + switch (State) + { + case AccountCreationDialogState.SigningIn: + StatusText.Text = "Account information is being saved."; + DialogIcon.Data = XamlHelpers.GetPathIcon("SavingAccountPathIcon"); + break; + case AccountCreationDialogState.PreparingFolders: + StatusText.Text = "We are getting folder information at the moment."; + DialogIcon.Data = XamlHelpers.GetPathIcon("PreparingFoldersPathIcon"); + break; + case AccountCreationDialogState.Completed: + StatusText.Text = "All done."; + break; + default: + break; + } + } + } +} diff --git a/Wino.Mail.WinUI/Dialogs/AccountEditDialog.xaml b/Wino.Mail.WinUI/Dialogs/AccountEditDialog.xaml new file mode 100644 index 00000000..34cba8f8 --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/AccountEditDialog.xaml @@ -0,0 +1,19 @@ + + + + + + diff --git a/Wino.Mail.WinUI/Dialogs/AccountEditDialog.xaml.cs b/Wino.Mail.WinUI/Dialogs/AccountEditDialog.xaml.cs new file mode 100644 index 00000000..0ea7efce --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/AccountEditDialog.xaml.cs @@ -0,0 +1,27 @@ + +using Wino.Core.Domain.Entities; + +#if NET8_0 +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml.Controls; +#endif +namespace Wino.Dialogs +{ + public sealed partial class AccountEditDialog : ContentDialog + { + public MailAccount Account { get; private set; } + public bool IsSaved { get; set; } + + public AccountEditDialog(MailAccount account) + { + InitializeComponent(); + Account = account; + } + + private void SaveClicked(ContentDialog sender, ContentDialogButtonClickEventArgs args) + { + IsSaved = true; + } + } +} diff --git a/Wino.Mail.WinUI/Dialogs/AccountPickerDialog.xaml b/Wino.Mail.WinUI/Dialogs/AccountPickerDialog.xaml new file mode 100644 index 00000000..f06da6d2 --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/AccountPickerDialog.xaml @@ -0,0 +1,19 @@ + + + + diff --git a/Wino.Mail.WinUI/Dialogs/AccountPickerDialog.xaml.cs b/Wino.Mail.WinUI/Dialogs/AccountPickerDialog.xaml.cs new file mode 100644 index 00000000..c2fb892e --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/AccountPickerDialog.xaml.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using Wino.Core.Domain.Entities; + +#if NET8_0 +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml.Controls; +#endif + +namespace Wino.Dialogs +{ + public sealed partial class AccountPickerDialog : ContentDialog + { + public MailAccount PickedAccount { get; set; } + + public List AvailableAccounts { get; set; } + + public AccountPickerDialog(List availableAccounts) + { + AvailableAccounts = availableAccounts; + + InitializeComponent(); + } + + private void AccountClicked(object sender, ItemClickEventArgs e) + { + PickedAccount = e.ClickedItem as MailAccount; + + Hide(); + } + } +} diff --git a/Wino.Mail.WinUI/Dialogs/AccountReorderDialog.xaml b/Wino.Mail.WinUI/Dialogs/AccountReorderDialog.xaml new file mode 100644 index 00000000..4f733a3a --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/AccountReorderDialog.xaml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wino.Mail.WinUI/Dialogs/AccountReorderDialog.xaml.cs b/Wino.Mail.WinUI/Dialogs/AccountReorderDialog.xaml.cs new file mode 100644 index 00000000..84bf6dae --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/AccountReorderDialog.xaml.cs @@ -0,0 +1,58 @@ +using System.Collections.ObjectModel; +using System.Linq; +using Microsoft.Extensions.DependencyInjection; +using Wino.Core.Domain.Interfaces; +using Wino.Mail.WinUI; + + +#if NET8_0 +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml.Controls; +#endif +namespace Wino.Dialogs +{ + public sealed partial class AccountReorderDialog : ContentDialog + { + public ObservableCollection Accounts { get; } + + private int count; + private bool isOrdering = false; + + private readonly IAccountService _accountService = App.Current.Services.GetService(); + + public AccountReorderDialog(ObservableCollection accounts) + { + Accounts = accounts; + + count = accounts.Count; + + InitializeComponent(); + } + + private void DialogOpened(ContentDialog sender, ContentDialogOpenedEventArgs args) + { + Accounts.CollectionChanged -= AccountsChanged; + Accounts.CollectionChanged += AccountsChanged; + } + + private void DialogClosed(ContentDialog sender, ContentDialogClosedEventArgs args) => Accounts.CollectionChanged -= AccountsChanged; + + private async void AccountsChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + if (count - 1 == Accounts.Count) + isOrdering = true; + + if (count == Accounts.Count && isOrdering) + { + // Order is completed. Apply changes. + + var dict = Accounts.ToDictionary(a => a.StartupEntityId, a => Accounts.IndexOf(a)); + + await _accountService.UpdateAccountOrdersAsync(dict); + + isOrdering = false; + } + } + } +} diff --git a/Wino.Mail.WinUI/Dialogs/BaseAccountCreationDialog.cs b/Wino.Mail.WinUI/Dialogs/BaseAccountCreationDialog.cs new file mode 100644 index 00000000..9aff2468 --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/BaseAccountCreationDialog.cs @@ -0,0 +1,58 @@ + +using Wino.Core.Domain.Enums; +using Wino.Core.Domain.Interfaces; + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +#endif +namespace Wino.Dialogs +{ + public abstract class BaseAccountCreationDialog : ContentDialog, IAccountCreationDialog + { + public AccountCreationDialogState State + { + get { return (AccountCreationDialogState)GetValue(StateProperty); } + set { SetValue(StateProperty, value); } + } + + public static readonly DependencyProperty StateProperty = DependencyProperty.Register(nameof(State), typeof(AccountCreationDialogState), typeof(BaseAccountCreationDialog), new PropertyMetadata(AccountCreationDialogState.Idle, OnStateChanged)); + + // Prevent users from dismissing it by ESC key. + private void DialogClosing(ContentDialog sender, ContentDialogClosingEventArgs args) + { + if (args.Result == ContentDialogResult.None) + { + args.Cancel = true; + } + } + + public void ShowDialog() + { + _ = ShowAsync(); + } + + public void Complete() + { + State = AccountCreationDialogState.Completed; + + // Unregister from closing event. + Closing -= DialogClosing; + + Hide(); + } + + private static void OnStateChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) + { + if (obj is BaseAccountCreationDialog dialog) + { + dialog.UpdateState(); + } + } + + public abstract void UpdateState(); + } +} diff --git a/Wino.Mail.WinUI/Dialogs/ConfirmationDialog.xaml b/Wino.Mail.WinUI/Dialogs/ConfirmationDialog.xaml new file mode 100644 index 00000000..5f7c5070 --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/ConfirmationDialog.xaml @@ -0,0 +1,29 @@ + + + + 250 + 500 + 200 + 756 + + + + diff --git a/Wino.Mail.WinUI/Dialogs/ConfirmationDialog.xaml.cs b/Wino.Mail.WinUI/Dialogs/ConfirmationDialog.xaml.cs new file mode 100644 index 00000000..b0dc5b1a --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/ConfirmationDialog.xaml.cs @@ -0,0 +1,86 @@ +using System.Threading.Tasks; +using Wino.Core.Domain.Interfaces; + +#if NET8_0 +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml; +#else +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml; +#endif + +namespace Wino.Dialogs +{ + public sealed partial class ConfirmationDialog : ContentDialog, IConfirmationDialog + { + private TaskCompletionSource _completionSource; + + #region Dependency Properties + + public string DialogTitle + { + get { return (string)GetValue(DialogTitleProperty); } + set { SetValue(DialogTitleProperty, value); } + } + + public static readonly DependencyProperty DialogTitleProperty = DependencyProperty.Register(nameof(DialogTitle), typeof(string), typeof(ConfirmationDialog), new PropertyMetadata(string.Empty)); + + public string Message + { + get { return (string)GetValue(MessageProperty); } + set { SetValue(MessageProperty, value); } + } + + public static readonly DependencyProperty MessageProperty = DependencyProperty.Register(nameof(Message), typeof(string), typeof(ConfirmationDialog), new PropertyMetadata(string.Empty)); + + public string ApproveButtonTitle + { + get { return (string)GetValue(ApproveButtonTitleProperty); } + set { SetValue(ApproveButtonTitleProperty, value); } + } + + public static readonly DependencyProperty ApproveButtonTitleProperty = DependencyProperty.Register(nameof(ApproveButtonTitle), typeof(string), typeof(ConfirmationDialog), new PropertyMetadata(string.Empty)); + + #endregion + + private bool _isApproved; + public ConfirmationDialog() + { + InitializeComponent(); + } + + public async Task ShowDialogAsync(string title, string message, string approveButtonTitle) + { + _completionSource = new TaskCompletionSource(); + + DialogTitle = title; + Message = message; + ApproveButtonTitle = approveButtonTitle; + +#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed + ShowAsync(); +#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed + + return await _completionSource.Task; + } + + private void DialogClosed(ContentDialog sender, ContentDialogClosedEventArgs args) + { + _completionSource.TrySetResult(_isApproved); + } + + private void ApproveClicked(ContentDialog sender, ContentDialogButtonClickEventArgs args) + { + _isApproved = true; + + Hide(); + } + + private void CancelClicked(ContentDialog sender, ContentDialogButtonClickEventArgs args) + { + _isApproved = false; + + Hide(); + } + } +} diff --git a/Wino.Mail.WinUI/Dialogs/CustomThemeBuilderDialog.xaml b/Wino.Mail.WinUI/Dialogs/CustomThemeBuilderDialog.xaml new file mode 100644 index 00000000..89e46480 --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/CustomThemeBuilderDialog.xaml @@ -0,0 +1,85 @@ + + + + 600 + 900 + 200 + 756 + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wino.Mail.WinUI/Dialogs/CustomThemeBuilderDialog.xaml.cs b/Wino.Mail.WinUI/Dialogs/CustomThemeBuilderDialog.xaml.cs new file mode 100644 index 00000000..1a0fc8a0 --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/CustomThemeBuilderDialog.xaml.cs @@ -0,0 +1,74 @@ +using System; +using CommunityToolkit.WinUI.Helpers; +using Microsoft.Extensions.DependencyInjection; +using Wino.Core.Domain.Interfaces; +using Wino.Mail.WinUI; + + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Media; +#else +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Media; +#endif + +namespace Wino.Dialogs +{ + public sealed partial class CustomThemeBuilderDialog : ContentDialog + { + public byte[] WallpaperData { get; private set; } + public string AccentColor { get; private set; } + + private IThemeService _themeService; + + public CustomThemeBuilderDialog() + { + InitializeComponent(); + + _themeService = App.Current.Services.GetService(); + } + + private async void ApplyClicked(ContentDialog sender, ContentDialogButtonClickEventArgs args) + { + if (Array.Empty() == WallpaperData) + return; + + var deferal = args.GetDeferral(); + + try + { + await _themeService.CreateNewCustomThemeAsync(ThemeNameBox.Text, AccentColor, WallpaperData); + } + catch (Exception exception) + { + ErrorTextBlock.Text = exception.Message; + } + finally + { + deferal.Complete(); + } + } + + private async void BrowseWallpaperClicked(object sender, RoutedEventArgs e) + { + var dialogService = App.Current.Services.GetService(); + + var pickedFileData = await dialogService.PickWindowsFileContentAsync(".jpg", ".png"); + + if (pickedFileData == Array.Empty()) return; + + IsPrimaryButtonEnabled = true; + + WallpaperData = pickedFileData; + } + + private void PickerColorChanged(Microsoft.UI.Xaml.Controls.ColorPicker sender, Microsoft.UI.Xaml.Controls.ColorChangedEventArgs args) + { + PreviewAccentColorGrid.Background = new SolidColorBrush(args.NewColor); + AccentColor = args.NewColor.ToHex(); + } + } +} diff --git a/Wino.Mail.WinUI/Dialogs/MoveMailDialog.xaml b/Wino.Mail.WinUI/Dialogs/MoveMailDialog.xaml new file mode 100644 index 00000000..970b300d --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/MoveMailDialog.xaml @@ -0,0 +1,59 @@ + + + + 600 + 600 + 756 + 756 + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wino.Mail.WinUI/Dialogs/MoveMailDialog.xaml.cs b/Wino.Mail.WinUI/Dialogs/MoveMailDialog.xaml.cs new file mode 100644 index 00000000..7cfcb998 --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/MoveMailDialog.xaml.cs @@ -0,0 +1,81 @@ +using System.Collections.Generic; +using Wino.Core.Domain; +using Wino.Core.Domain.Models.Folders; + +#if NET8_0 +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml; +#else +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml; +#endif + +namespace Wino.Dialogs +{ + public sealed partial class MoveMailDialog : ContentDialog + { + public IMailItemFolder SelectedFolder + { + get { return (IMailItemFolder)GetValue(SelectedFolderProperty); } + set { SetValue(SelectedFolderProperty, value); } + } + + public static readonly DependencyProperty SelectedFolderProperty = DependencyProperty.Register(nameof(SelectedFolder), typeof(IMailItemFolder), typeof(MoveMailDialog), new PropertyMetadata(null, OnSelectedFolderChanged)); + + + public List FolderList { get; set; } + + public MoveMailDialog(List allFolders) + { + InitializeComponent(); + + if (allFolders == null) return; + + FolderList = allFolders; + } + + private static void OnSelectedFolderChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) + { + if (obj is MoveMailDialog dialog) + { + dialog.VerifySelection(); + } + } + + private void VerifySelection() + { + if (SelectedFolder != null) + { + // Don't select non-move capable folders like Categories or More. + + if (!SelectedFolder.IsMoveTarget) + { + // Warn users for only proper mail folders. Not ghost folders. + InvalidFolderText.Visibility = Visibility.Visible; + InvalidFolderText.Text = string.Format(Translator.MoveMailDialog_InvalidFolderMessage, SelectedFolder.FolderName); + + if (FolderTreeView.SelectedItem != null) + { + // Toggle the expansion for the selected container if available. + // I don't like the expand arrow touch area. It's better this way. + + if (FolderTreeView.ContainerFromItem(FolderTreeView.SelectedItem) is Microsoft.UI.Xaml.Controls.TreeViewItem container) + { + container.IsExpanded = !container.IsExpanded; + } + } + SelectedFolder = null; + } + else + { + Hide(); + } + } + } + + private void CancelClicked(ContentDialog sender, ContentDialogButtonClickEventArgs args) + { + Hide(); + } + } +} diff --git a/Wino.Mail.WinUI/Dialogs/NewAccountDialog.xaml b/Wino.Mail.WinUI/Dialogs/NewAccountDialog.xaml new file mode 100644 index 00000000..a763228a --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/NewAccountDialog.xaml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wino.Mail.WinUI/Dialogs/NewAccountDialog.xaml.cs b/Wino.Mail.WinUI/Dialogs/NewAccountDialog.xaml.cs new file mode 100644 index 00000000..a2e4f0e8 --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/NewAccountDialog.xaml.cs @@ -0,0 +1,91 @@ +using System.Collections.Generic; +using Wino.Core.Domain.Interfaces; +using Wino.Core.Domain.Models.Accounts; + +#if NET8_0 +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml; +#else +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml; +#endif + +namespace Wino.Dialogs +{ + public sealed partial class NewAccountDialog : ContentDialog + { + /// + /// Gets or sets current selected mail provider in the dialog. + /// + public ProviderDetail SelectedMailProvider + { + get { return (ProviderDetail)GetValue(SelectedMailProviderProperty); } + set { SetValue(SelectedMailProviderProperty, value); } + } + + public static readonly DependencyProperty SelectedMailProviderProperty = DependencyProperty.Register(nameof(SelectedMailProvider), typeof(ProviderDetail), typeof(NewAccountDialog), new PropertyMetadata(null, new PropertyChangedCallback(OnSelectedProviderChanged))); + + // List of available mail providers for now. + + public List Providers { get; set; } + + public AccountCreationDialogResult Result = null; + + public NewAccountDialog() + { + InitializeComponent(); + + // AccountColorPicker.Color = Colors.Blue; + } + + private static void OnSelectedProviderChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) + { + if (obj is NewAccountDialog dialog) + dialog.Validate(); + } + + private void CancelClicked(ContentDialog sender, ContentDialogButtonClickEventArgs args) + { + Hide(); + } + + private void CreateClicked(ContentDialog sender, ContentDialogButtonClickEventArgs args) + { + Validate(); + + if (IsSecondaryButtonEnabled) + { + Result = new AccountCreationDialogResult(SelectedMailProvider.Type, AccountNameTextbox.Text.Trim(), SenderNameTextbox.Text.Trim()); + Hide(); + } + } + + private void AccountNameChanged(object sender, TextChangedEventArgs e) => Validate(); + private void SenderNameChanged(object sender, TextChangedEventArgs e) => Validate(); + + private void Validate() + { + ValidateCreateButton(); + ValidateNames(); + } + + // Returns whether we can create account or not. + private void ValidateCreateButton() + { + bool shouldEnable = SelectedMailProvider != null + && SelectedMailProvider.IsSupported + && !string.IsNullOrEmpty(AccountNameTextbox.Text) + && (SelectedMailProvider.RequireSenderNameOnCreationDialog ? !string.IsNullOrEmpty(SenderNameTextbox.Text) : true); + + IsPrimaryButtonEnabled = shouldEnable; + } + + private void ValidateNames() + { + AccountNameTextbox.IsEnabled = SelectedMailProvider != null; + SenderNameTextbox.IsEnabled = SelectedMailProvider != null && SelectedMailProvider.Type != Core.Domain.Enums.MailProviderType.IMAP4; + } + + private void DialogOpened(ContentDialog sender, ContentDialogOpenedEventArgs args) => Validate(); + } +} diff --git a/Wino.Mail.WinUI/Dialogs/NewImapSetupDialog.xaml b/Wino.Mail.WinUI/Dialogs/NewImapSetupDialog.xaml new file mode 100644 index 00000000..09ffaba7 --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/NewImapSetupDialog.xaml @@ -0,0 +1,25 @@ + + + + 0,0,0,0 + + 1920 + + + + + diff --git a/Wino.Mail.WinUI/Dialogs/NewImapSetupDialog.xaml.cs b/Wino.Mail.WinUI/Dialogs/NewImapSetupDialog.xaml.cs new file mode 100644 index 00000000..9bfceacd --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/NewImapSetupDialog.xaml.cs @@ -0,0 +1,104 @@ +using System; +using System.Threading.Tasks; +using CommunityToolkit.Mvvm.Messaging; + +using Wino.Core.Domain.Entities; +using Wino.Core.Domain.Enums; +using Wino.Core.Domain.Interfaces; +using Wino.Core.Messages.Mails; +using Wino.Views.ImapSetup; + + +#if NET8_0 +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Media.Animation; +#else +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Media.Animation; +#endif + +namespace Wino.Dialogs +{ + public enum ImapSetupState + { + Welcome, + AutoDiscovery, + TestingConnection, + PreparingFolder + } + + public sealed partial class NewImapSetupDialog : ContentDialog, + IRecipient, + IRecipient, + IRecipient, + ICustomServerAccountCreationDialog + { + private TaskCompletionSource _getServerInfoTaskCompletionSource = new TaskCompletionSource(); + + private bool isDismissRequested = false; + + public NewImapSetupDialog() + { + InitializeComponent(); + } + + // Not used for now. + public AccountCreationDialogState State { get; set; } + + public void Complete() + { + if (!_getServerInfoTaskCompletionSource.Task.IsCompleted) + _getServerInfoTaskCompletionSource.TrySetResult(null); + + isDismissRequested = true; + + Hide(); + } + + public Task GetCustomServerInformationAsync() => _getServerInfoTaskCompletionSource.Task; + + public async void Receive(ImapSetupBackNavigationRequested message) + { + // Frame go back + if (message.PageType == null) + { + if (ImapFrame.CanGoBack) + { + // Go back using Dispatcher to allow navigations in OnNavigatedTo. + await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => + { + ImapFrame.GoBack(); + }); + } + } + else + { + ImapFrame.Navigate(message.PageType, message.Parameter, new SlideNavigationTransitionInfo() { Effect = SlideNavigationTransitionEffect.FromLeft }); + } + } + + public void Receive(ImapSetupNavigationRequested message) + { + ImapFrame.Navigate(message.PageType, message.Parameter, new SlideNavigationTransitionInfo() { Effect = SlideNavigationTransitionEffect.FromRight }); + } + + public void Receive(ImapSetupDismissRequested message) => _getServerInfoTaskCompletionSource.TrySetResult(message.CompletedServerInformation); + + public void ShowDialog() => _ = ShowAsync(); + + public void ShowPreparingFolders() + { + ImapFrame.Navigate(typeof(PreparingImapFoldersPage), new SlideNavigationTransitionInfo() { Effect = SlideNavigationTransitionEffect.FromLeft }); + } + + public void StartImapConnectionSetup(MailAccount account) => ImapFrame.Navigate(typeof(WelcomeImapSetupPage), account, new DrillInNavigationTransitionInfo()); + + + private void ImapSetupDialogClosed(ContentDialog sender, ContentDialogClosedEventArgs args) => WeakReferenceMessenger.Default.UnregisterAll(this); + + private void ImapSetupDialogOpened(ContentDialog sender, ContentDialogOpenedEventArgs args) => WeakReferenceMessenger.Default.RegisterAll(this); + + // Don't hide the dialog unless dismiss is requested from the inner pages specifically. + private void OnDialogClosing(ContentDialog sender, ContentDialogClosingEventArgs args) => args.Cancel = !isDismissRequested; + } +} diff --git a/Wino.Mail.WinUI/Dialogs/SignatureEditorDialog.xaml b/Wino.Mail.WinUI/Dialogs/SignatureEditorDialog.xaml new file mode 100644 index 00000000..3326191c --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/SignatureEditorDialog.xaml @@ -0,0 +1,262 @@ + + + + 1200 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wino.Mail.WinUI/Dialogs/SignatureEditorDialog.xaml.cs b/Wino.Mail.WinUI/Dialogs/SignatureEditorDialog.xaml.cs new file mode 100644 index 00000000..99c99720 --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/SignatureEditorDialog.xaml.cs @@ -0,0 +1,379 @@ +using System; +using System.Text.RegularExpressions; +using System.Text.Json; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Web.WebView2.Core; +using Windows.UI.ViewManagement.Core; +using Wino.Core.Domain; +using Wino.Core.Domain.Entities; +using Wino.Core.Domain.Interfaces; +using Wino.Core.Domain.Models.Reader; +using Wino.Views.Settings; +using Wino.Mail.WinUI; + + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +#endif + +namespace Wino.Dialogs +{ + public sealed partial class SignatureEditorDialog : ContentDialog + { + private Func> _getHTMLBodyFunction; + private readonly TaskCompletionSource _domLoadedTask = new TaskCompletionSource(); + private readonly INativeAppService _nativeAppService = App.Current.Services.GetService(); + public AccountSignature Result; + + public bool IsComposerDarkMode + { + get { return (bool)GetValue(IsComposerDarkModeProperty); } + set { SetValue(IsComposerDarkModeProperty, value); } + } + + public static readonly DependencyProperty IsComposerDarkModeProperty = DependencyProperty.Register(nameof(IsComposerDarkMode), typeof(bool), typeof(SignatureManagementPage), new PropertyMetadata(false, OnIsComposerDarkModeChanged)); + + public SignatureEditorDialog() + { + InitializeComponent(); + + SignatureNameTextBox.Header = Translator.SignatureEditorDialog_SignatureName_TitleNew; + Environment.SetEnvironmentVariable("WEBVIEW2_DEFAULT_BACKGROUND_COLOR", "00FFFFFF"); + Environment.SetEnvironmentVariable("WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS", "--enable-features=OverlayScrollbar,msOverlayScrollbarWinStyle,msOverlayScrollbarWinStyleAnimation"); + + // TODO: Should be added additional logic to enable/disable primary button when webview content changed. + IsPrimaryButtonEnabled = true; + } + + public SignatureEditorDialog(AccountSignature signatureModel) + { + InitializeComponent(); + + SignatureNameTextBox.Text = signatureModel.Name.Trim(); + SignatureNameTextBox.Header = string.Format(Translator.SignatureEditorDialog_SignatureName_TitleEdit, signatureModel.Name); + + Result = new AccountSignature + { + Id = signatureModel.Id, + Name = signatureModel.Name, + MailAccountId = signatureModel.MailAccountId, + HtmlBody = signatureModel.HtmlBody + }; + Environment.SetEnvironmentVariable("WEBVIEW2_DEFAULT_BACKGROUND_COLOR", "00FFFFFF"); + Environment.SetEnvironmentVariable("WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS", "--enable-features=OverlayScrollbar,msOverlayScrollbarWinStyle,msOverlayScrollbarWinStyleAnimation"); + + // TODO: Should be added additional logic to enable/disable primary button when webview content changed. + IsPrimaryButtonEnabled = true; + } + + private async void SignatureDialogOpened(ContentDialog sender, ContentDialogOpenedEventArgs args) + { + Chromium.CoreWebView2Initialized -= ChromiumInitialized; + Chromium.CoreWebView2Initialized += ChromiumInitialized; + + await Chromium.EnsureCoreWebView2Async(); + + _getHTMLBodyFunction = new Func>(async () => + { + var editorContent = await InvokeScriptSafeAsync("GetHTMLContent();"); + + return JsonSerializer.Deserialize(editorContent); + }); + + var underlyingThemeService = App.Current.Services.GetService(); + + IsComposerDarkMode = underlyingThemeService.IsUnderlyingThemeDark(); + + await RenderInternalAsync(Result?.HtmlBody ?? string.Empty); + } + + private void DialogClosed(ContentDialog sender, ContentDialogClosedEventArgs args) + { + Chromium.CoreWebView2Initialized -= ChromiumInitialized; + + if (Chromium.CoreWebView2 != null) + { + Chromium.CoreWebView2.DOMContentLoaded -= DOMLoaded; + Chromium.CoreWebView2.WebMessageReceived -= ScriptMessageReceived; + } + } + + private async void SaveClicked(ContentDialog sender, ContentDialogButtonClickEventArgs args) + { + var newSignature = Regex.Unescape(await _getHTMLBodyFunction()); + + if (Result == null) + { + Result = new AccountSignature + { + Id = Guid.NewGuid(), + Name = SignatureNameTextBox.Text.Trim(), + HtmlBody = newSignature + }; + } + else + { + Result.Name = SignatureNameTextBox.Text.Trim(); + Result.HtmlBody = newSignature; + } + + Hide(); + } + + private void CancelClicked(ContentDialog sender, ContentDialogButtonClickEventArgs args) + { + Hide(); + } + + private async void BoldButtonClicked(object sender, RoutedEventArgs e) + { + await InvokeScriptSafeAsync("editor.execCommand('bold')"); + } + + private async void ItalicButtonClicked(object sender, RoutedEventArgs e) + { + await InvokeScriptSafeAsync("editor.execCommand('italic')"); + } + + private async void UnderlineButtonClicked(object sender, RoutedEventArgs e) + { + await InvokeScriptSafeAsync("editor.execCommand('underline')"); + } + + private async void StrokeButtonClicked(object sender, RoutedEventArgs e) + { + await InvokeScriptSafeAsync("editor.execCommand('strikethrough')"); + } + + private async void BulletListButtonClicked(object sender, RoutedEventArgs e) + { + await InvokeScriptSafeAsync("editor.execCommand('insertunorderedlist')"); + } + + private async void OrderedListButtonClicked(object sender, RoutedEventArgs e) + { + await InvokeScriptSafeAsync("editor.execCommand('insertorderedlist')"); + } + + private async void IncreaseIndentClicked(object sender, RoutedEventArgs e) + { + await InvokeScriptSafeAsync("editor.execCommand('indent')"); + } + + private async void DecreaseIndentClicked(object sender, RoutedEventArgs e) + { + await InvokeScriptSafeAsync("editor.execCommand('outdent')"); + } + + private async void AlignmentChanged(object sender, SelectionChangedEventArgs e) + { + var selectedItem = AlignmentListView.SelectedItem as ComboBoxItem; + var alignment = selectedItem.Tag.ToString(); + + switch (alignment) + { + case "left": + await InvokeScriptSafeAsync("editor.execCommand('justifyleft')"); + break; + case "center": + await InvokeScriptSafeAsync("editor.execCommand('justifycenter')"); + break; + case "right": + await InvokeScriptSafeAsync("editor.execCommand('justifyright')"); + break; + case "justify": + await InvokeScriptSafeAsync("editor.execCommand('justifyfull')"); + break; + } + } + + public async Task ExecuteScriptFunctionAsync(string functionName, params object[] parameters) + { + string script = functionName + "("; + for (int i = 0; i < parameters.Length; i++) + { + script += JsonSerializer.Serialize(parameters[i]); + if (i < parameters.Length - 1) + { + script += ", "; + } + } + script += ");"; + + return await Chromium.ExecuteScriptAsync(script); + } + + private async Task InvokeScriptSafeAsync(string function) + { + if (Chromium == null) return string.Empty; + + try + { + + return await Chromium.ExecuteScriptAsync(function); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + + return string.Empty; + } + + private async void AddImageClicked(object sender, RoutedEventArgs e) + { + await InvokeScriptSafeAsync("imageInput.click();"); + } + + private async Task FocusEditorAsync() + { + await InvokeScriptSafeAsync("editor.selection.focus();"); + + Chromium.Focus(FocusState.Keyboard); + Chromium.Focus(FocusState.Programmatic); + } + + private async void EmojiButtonClicked(object sender, RoutedEventArgs e) + { + CoreInputView.GetForCurrentView().TryShow(CoreInputViewKind.Emoji); + + await FocusEditorAsync(); + } + + private async Task TryGetSelectedTextAsync() + { + try + { + return await Chromium.ExecuteScriptAsync("getSelectedText();"); + } + catch { } + + return string.Empty; + } + + private async void WebViewToggleButtonClicked(object sender, RoutedEventArgs e) + { + var enable = WebviewToolBarButton.IsChecked == true ? "true" : "false"; + await InvokeScriptSafeAsync($"toggleToolbar('{enable}');"); + } + + private async Task UpdateEditorThemeAsync() + { + await _domLoadedTask.Task; + + if (IsComposerDarkMode) + { + Chromium.CoreWebView2.Profile.PreferredColorScheme = CoreWebView2PreferredColorScheme.Dark; + await InvokeScriptSafeAsync("SetDarkEditor();"); + } + else + { + Chromium.CoreWebView2.Profile.PreferredColorScheme = CoreWebView2PreferredColorScheme.Light; + await InvokeScriptSafeAsync("SetLightEditor();"); + } + } + + private async Task RenderInternalAsync(string htmlBody) + { + await _domLoadedTask.Task; + + await UpdateEditorThemeAsync(); + + if (string.IsNullOrEmpty(htmlBody)) + { + await ExecuteScriptFunctionAsync("RenderHTML", " "); + } + else + { + await ExecuteScriptFunctionAsync("RenderHTML", htmlBody); + + await FocusEditorAsync(); + } + } + + private async void ChromiumInitialized(Microsoft.UI.Xaml.Controls.WebView2 sender, Microsoft.UI.Xaml.Controls.CoreWebView2InitializedEventArgs args) + { + var editorBundlePath = (await _nativeAppService.GetEditorBundlePathAsync()).Replace("editor.html", string.Empty); + + Chromium.CoreWebView2.SetVirtualHostNameToFolderMapping("app.editor", editorBundlePath, CoreWebView2HostResourceAccessKind.Allow); + Chromium.Source = new Uri("https://app.editor/editor.html"); + + Chromium.CoreWebView2.DOMContentLoaded -= DOMLoaded; + Chromium.CoreWebView2.DOMContentLoaded += DOMLoaded; + + Chromium.CoreWebView2.WebMessageReceived -= ScriptMessageReceived; + Chromium.CoreWebView2.WebMessageReceived += ScriptMessageReceived; + } + + private static async void OnIsComposerDarkModeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) + { + if (obj is SignatureEditorDialog dialog) + { + await dialog.UpdateEditorThemeAsync(); + } + } + + private void ScriptMessageReceived(CoreWebView2 sender, CoreWebView2WebMessageReceivedEventArgs args) + { + var change = JsonSerializer.Deserialize(args.WebMessageAsJson); + + if (change.Type == "bold") + { + BoldButton.IsChecked = change.Value == "true"; + } + else if (change.Type == "italic") + { + ItalicButton.IsChecked = change.Value == "true"; + } + else if (change.Type == "underline") + { + UnderlineButton.IsChecked = change.Value == "true"; + } + else if (change.Type == "strikethrough") + { + StrokeButton.IsChecked = change.Value == "true"; + } + else if (change.Type == "ol") + { + OrderedListButton.IsChecked = change.Value == "true"; + } + else if (change.Type == "ul") + { + BulletListButton.IsChecked = change.Value == "true"; + } + else if (change.Type == "indent") + { + IncreaseIndentButton.IsEnabled = change.Value == "disabled" ? false : true; + } + else if (change.Type == "outdent") + { + DecreaseIndentButton.IsEnabled = change.Value == "disabled" ? false : true; + } + else if (change.Type == "alignment") + { + var parsedValue = change.Value switch + { + "jodit-icon_left" => 0, + "jodit-icon_center" => 1, + "jodit-icon_right" => 2, + "jodit-icon_justify" => 3, + _ => 0 + }; + AlignmentListView.SelectionChanged -= AlignmentChanged; + AlignmentListView.SelectedIndex = parsedValue; + AlignmentListView.SelectionChanged += AlignmentChanged; + } + } + + private void DOMLoaded(CoreWebView2 sender, CoreWebView2DOMContentLoadedEventArgs args) => _domLoadedTask.TrySetResult(true); + + private void SignatureNameTextBoxTextChanged(object sender, TextChangedEventArgs e) => IsPrimaryButtonEnabled = !string.IsNullOrWhiteSpace(SignatureNameTextBox.Text); + + private void InvertComposerThemeClicked(object sender, RoutedEventArgs e) => IsComposerDarkMode = !IsComposerDarkMode; + } +} diff --git a/Wino.Mail.WinUI/Dialogs/StoreRatingDialog.xaml b/Wino.Mail.WinUI/Dialogs/StoreRatingDialog.xaml new file mode 100644 index 00000000..be839312 --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/StoreRatingDialog.xaml @@ -0,0 +1,24 @@ + + + + + + + + + + diff --git a/Wino.Mail.WinUI/Dialogs/StoreRatingDialog.xaml.cs b/Wino.Mail.WinUI/Dialogs/StoreRatingDialog.xaml.cs new file mode 100644 index 00000000..8d025c2c --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/StoreRatingDialog.xaml.cs @@ -0,0 +1,25 @@ +using Wino.Core.Domain.Interfaces; + +#if NET8_0 +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml.Controls; +#endif +namespace Wino.Dialogs +{ + public sealed partial class StoreRatingDialog : ContentDialog, IStoreRatingDialog + { + public bool DontAskAgain { get; set; } + public bool RateWinoClicked { get; set; } + + public StoreRatingDialog() + { + this.InitializeComponent(); + } + + private void RateClicked(ContentDialog sender, ContentDialogButtonClickEventArgs args) + { + RateWinoClicked = true; + } + } +} diff --git a/Wino.Mail.WinUI/Dialogs/SystemFolderConfigurationDialog.xaml b/Wino.Mail.WinUI/Dialogs/SystemFolderConfigurationDialog.xaml new file mode 100644 index 00000000..44b98813 --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/SystemFolderConfigurationDialog.xaml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wino.Mail.WinUI/Dialogs/SystemFolderConfigurationDialog.xaml.cs b/Wino.Mail.WinUI/Dialogs/SystemFolderConfigurationDialog.xaml.cs new file mode 100644 index 00000000..c19e3532 --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/SystemFolderConfigurationDialog.xaml.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Wino.Core.Domain; +using Wino.Core.Domain.Entities; +using Wino.Core.Domain.Enums; + +#if NET8_0 +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml.Controls; +#endif +namespace Wino.Dialogs +{ + public sealed partial class SystemFolderConfigurationDialog : ContentDialog + { + private bool canDismissDialog = false; + + public SystemFolderConfiguration Configuration { get; set; } + public List AvailableFolders { get; } + + public MailItemFolder Sent { get; set; } + public MailItemFolder Draft { get; set; } + public MailItemFolder Archive { get; set; } + public MailItemFolder Junk { get; set; } + public MailItemFolder Trash { get; set; } + + public SystemFolderConfigurationDialog(List availableFolders) + { + InitializeComponent(); + + AvailableFolders = availableFolders; + + Sent = AvailableFolders.Find(a => a.SpecialFolderType == Core.Domain.Enums.SpecialFolderType.Sent); + Draft = AvailableFolders.Find(a => a.SpecialFolderType == Core.Domain.Enums.SpecialFolderType.Draft); + Archive = AvailableFolders.Find(a => a.SpecialFolderType == Core.Domain.Enums.SpecialFolderType.Archive); + Junk = AvailableFolders.Find(a => a.SpecialFolderType == Core.Domain.Enums.SpecialFolderType.Junk); + Trash = AvailableFolders.Find(a => a.SpecialFolderType == Core.Domain.Enums.SpecialFolderType.Deleted); + } + + private void DialogClosing(ContentDialog sender, ContentDialogClosingEventArgs args) + { + args.Cancel = !canDismissDialog; + } + + private void CancelClicked(ContentDialog sender, ContentDialogButtonClickEventArgs args) + => canDismissDialog = true; + + private void SaveClicked(ContentDialog sender, ContentDialogButtonClickEventArgs args) + { + ValidationErrorTextBlock.Text = string.Empty; + + var allSpecialFolders = new List() + { + Sent, Draft, Archive, Trash, Junk + }; + + if (allSpecialFolders.Any(a => a != null && a.SpecialFolderType == SpecialFolderType.Inbox)) + ValidationErrorTextBlock.Text = Translator.SystemFolderConfigDialogValidation_InboxSelected; + + if (new HashSet(allSpecialFolders.Where(a => a != null).Select(x => x.Id)).Count != allSpecialFolders.Where(a => a != null).Count()) + ValidationErrorTextBlock.Text = Translator.SystemFolderConfigDialogValidation_DuplicateSystemFolders; + + // Check if we can save. + if (string.IsNullOrEmpty(ValidationErrorTextBlock.Text)) + { + var configuration = new SystemFolderConfiguration(Sent, Draft, Archive, Trash, Junk); + + canDismissDialog = true; + Configuration = configuration; + } + } + } +} diff --git a/Wino.Mail.WinUI/Dialogs/TextInputDialog.xaml b/Wino.Mail.WinUI/Dialogs/TextInputDialog.xaml new file mode 100644 index 00000000..6ca651f1 --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/TextInputDialog.xaml @@ -0,0 +1,28 @@ + + + + 400 + 400 + 200 + 756 + + + + + + + diff --git a/Wino.Mail.WinUI/Dialogs/TextInputDialog.xaml.cs b/Wino.Mail.WinUI/Dialogs/TextInputDialog.xaml.cs new file mode 100644 index 00000000..0e75d0f7 --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/TextInputDialog.xaml.cs @@ -0,0 +1,51 @@ + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +#endif + +namespace Wino.Dialogs +{ + public sealed partial class TextInputDialog : ContentDialog + { + public bool? HasInput { get; set; } + + public string CurrentInput + { + get { return (string)GetValue(CurrentInputProperty); } + set { SetValue(CurrentInputProperty, value); } + } + + public static readonly DependencyProperty CurrentInputProperty = DependencyProperty.Register(nameof(CurrentInput), typeof(string), typeof(TextInputDialog), new PropertyMetadata(string.Empty)); + + public TextInputDialog() + { + InitializeComponent(); + } + + public void SetDescription(string description) + { + DialogDescription.Text = description; + } + + public void SetPrimaryButtonText(string text) + { + PrimaryButtonText = text; + } + + private void CancelClicked(ContentDialog sender, ContentDialogButtonClickEventArgs args) + { + Hide(); + } + + private void UpdateOrCreateClicked(ContentDialog sender, ContentDialogButtonClickEventArgs args) + { + HasInput = true; + + Hide(); + } + } +} diff --git a/Wino.Mail.WinUI/Dialogs/WinoMessageDialog.xaml b/Wino.Mail.WinUI/Dialogs/WinoMessageDialog.xaml new file mode 100644 index 00000000..d61fc010 --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/WinoMessageDialog.xaml @@ -0,0 +1,25 @@ + + + + 250 + 900 + 200 + 756 + + + + diff --git a/Wino.Mail.WinUI/Dialogs/WinoMessageDialog.xaml.cs b/Wino.Mail.WinUI/Dialogs/WinoMessageDialog.xaml.cs new file mode 100644 index 00000000..b4a90600 --- /dev/null +++ b/Wino.Mail.WinUI/Dialogs/WinoMessageDialog.xaml.cs @@ -0,0 +1,65 @@ +using System.Threading.Tasks; + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +#endif +namespace Wino.Dialogs +{ + public sealed partial class WinoMessageDialog : ContentDialog + { + private TaskCompletionSource _completionSource; + + #region Dependency Properties + + public string DialogTitle + { + get { return (string)GetValue(DialogTitleProperty); } + set { SetValue(DialogTitleProperty, value); } + } + + public static readonly DependencyProperty DialogTitleProperty = DependencyProperty.Register(nameof(DialogTitle), typeof(string), typeof(ConfirmationDialog), new PropertyMetadata(string.Empty)); + + public string Message + { + get { return (string)GetValue(MessageProperty); } + set { SetValue(MessageProperty, value); } + } + + public static readonly DependencyProperty MessageProperty = DependencyProperty.Register(nameof(Message), typeof(string), typeof(ConfirmationDialog), new PropertyMetadata(string.Empty)); + + #endregion + + public WinoMessageDialog() + { + InitializeComponent(); + } + + public async Task ShowDialogAsync(string title, string message) + { + _completionSource = new TaskCompletionSource(); + + DialogTitle = title; + Message = message; + +#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed + ShowAsync(); +#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed + + return await _completionSource.Task; + } + + private void ApproveClicked(object sender, RoutedEventArgs e) + { + Hide(); + } + + private void DialogClosed(ContentDialog sender, ContentDialogClosedEventArgs args) + { + _completionSource.TrySetResult(true); + } + } +} diff --git a/Wino.Mail.WinUI/Extensions/AnimationExtensions.cs b/Wino.Mail.WinUI/Extensions/AnimationExtensions.cs new file mode 100644 index 00000000..da45280c --- /dev/null +++ b/Wino.Mail.WinUI/Extensions/AnimationExtensions.cs @@ -0,0 +1,119 @@ +using System; +using System.Numerics; + + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Media.Animation; +using Microsoft.UI.Composition; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Media.Animation; +using Windows.UI.Composition; +#endif +namespace Wino.Extensions +{ + public static class AnimationExtensions + { + #region Composition + + public static ScalarKeyFrameAnimation CreateScalarKeyFrameAnimation(this Compositor compositor, float? from, float to, + double duration, double delay, CompositionEasingFunction easing, AnimationIterationBehavior iterationBehavior) + { + var animation = compositor.CreateScalarKeyFrameAnimation(); + + animation.Duration = TimeSpan.FromMilliseconds(duration); + if (!delay.Equals(0)) animation.DelayTime = TimeSpan.FromMilliseconds(delay); + if (from.HasValue) animation.InsertKeyFrame(0.0f, from.Value, easing); + animation.InsertKeyFrame(1.0f, to, easing); + animation.IterationBehavior = iterationBehavior; + + return animation; + } + + public static Vector2KeyFrameAnimation CreateVector2KeyFrameAnimation(this Compositor compositor, Vector2? from, Vector2 to, + double duration, double delay, CompositionEasingFunction easing, AnimationIterationBehavior iterationBehavior) + { + var animation = compositor.CreateVector2KeyFrameAnimation(); + + animation.Duration = TimeSpan.FromMilliseconds(duration); + animation.DelayTime = TimeSpan.FromMilliseconds(delay); + if (from.HasValue) animation.InsertKeyFrame(0.0f, from.Value, easing); + animation.InsertKeyFrame(1.0f, to, easing); + animation.IterationBehavior = iterationBehavior; + + return animation; + } + + public static Vector3KeyFrameAnimation CreateVector3KeyFrameAnimation(this Compositor compositor, Vector2? from, Vector2 to, + double duration, double delay, CompositionEasingFunction easing, AnimationIterationBehavior iterationBehavior) + { + var animation = compositor.CreateVector3KeyFrameAnimation(); + + animation.Duration = TimeSpan.FromMilliseconds(duration); + animation.DelayTime = TimeSpan.FromMilliseconds(delay); + if (from.HasValue) animation.InsertKeyFrame(0.0f, new Vector3(from.Value, 1.0f), easing); + animation.InsertKeyFrame(1.0f, new Vector3(to, 1.0f), easing); + animation.IterationBehavior = iterationBehavior; + + return animation; + } + + public static Vector3KeyFrameAnimation CreateVector3KeyFrameAnimation(this Compositor compositor, Vector3? from, Vector3 to, + double duration, double delay, CompositionEasingFunction easing, AnimationIterationBehavior iterationBehavior) + { + var animation = compositor.CreateVector3KeyFrameAnimation(); + + animation.Duration = TimeSpan.FromMilliseconds(duration); + animation.DelayTime = TimeSpan.FromMilliseconds(delay); + if (from.HasValue) animation.InsertKeyFrame(0.0f, from.Value, easing); + animation.InsertKeyFrame(1.0f, to, easing); + animation.IterationBehavior = iterationBehavior; + + return animation; + } + + #endregion + + #region Xaml Storyboard + + public static void Animate(this DependencyObject target, double? from, double to, + string propertyPath, int duration = 400, int startTime = 0, + EasingFunctionBase easing = null, Action completed = null, bool enableDependentAnimation = false) + { + if (easing == null) + { + easing = new ExponentialEase(); + } + + var db = new DoubleAnimation + { + EnableDependentAnimation = enableDependentAnimation, + To = to, + From = from, + EasingFunction = easing, + Duration = TimeSpan.FromMilliseconds(duration) + }; + Storyboard.SetTarget(db, target); + Storyboard.SetTargetProperty(db, propertyPath); + + var sb = new Storyboard + { + BeginTime = TimeSpan.FromMilliseconds(startTime) + }; + + if (completed != null) + { + sb.Completed += (s, e) => + { + completed(); + }; + } + + sb.Children.Add(db); + sb.Begin(); + } + + #endregion + } +} diff --git a/Wino.Mail.WinUI/Extensions/CompositionEnums.cs b/Wino.Mail.WinUI/Extensions/CompositionEnums.cs new file mode 100644 index 00000000..d307311e --- /dev/null +++ b/Wino.Mail.WinUI/Extensions/CompositionEnums.cs @@ -0,0 +1,69 @@ +using System; + +namespace Wino.Extensions +{ + public enum TransitionDirection + { + TopToBottom, + BottomToTop, + LeftToRight, + RightToLeft + } + + public enum ClipAnimationDirection + { + Top, + Bottom, + Left, + Right + } + + public enum AnimationAxis + { + X, + Y, + Z + } + + public enum AnimationType + { + KeyFrame, + Expression + } + + public enum FlickDirection + { + None, + Up, + Down, + Left, + Right + } + + public enum ViewState + { + Empty, + Small, + Big, + Full + } + + public enum Gesture + { + Initial, + Tap, + Swipe + } + + [Flags] + public enum VisualPropertyType + { + None = 0, + Opacity = 1 << 0, + Offset = 1 << 1, + Scale = 1 << 2, + Size = 1 << 3, + RotationAngleInDegrees = 1 << 4, + All = ~0 + } +} diff --git a/Wino.Mail.WinUI/Extensions/CompositionExtensions.Implicit.cs b/Wino.Mail.WinUI/Extensions/CompositionExtensions.Implicit.cs new file mode 100644 index 00000000..b61608db --- /dev/null +++ b/Wino.Mail.WinUI/Extensions/CompositionExtensions.Implicit.cs @@ -0,0 +1,202 @@ +using System; +using System.Numerics; + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Hosting; +using Microsoft.UI.Composition; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Hosting; +using Windows.UI.Composition; +#endif +namespace Wino.Extensions +{ + public static partial class CompositionExtensions + { + public static void EnableFluidVisibilityAnimation(this UIElement element, AnimationAxis? axis = null, + float showFromOffset = 0.0f, float hideToOffset = 0.0f, Vector3? centerPoint = null, + float showFromScale = 1.0f, float hideToScale = 1.0f, float showDuration = 800.0f, float hideDuration = 800.0f, + int showDelay = 0, int hideDelay = 0, bool animateOpacity = true) + { + var elementVisual = element.Visual(); + var compositor = elementVisual.Compositor; + ElementCompositionPreview.SetIsTranslationEnabled(element, true); + + ScalarKeyFrameAnimation hideOpacityAnimation = null; + ScalarKeyFrameAnimation showOpacityAnimation = null; + ScalarKeyFrameAnimation hideOffsetAnimation = null; + ScalarKeyFrameAnimation showOffsetAnimation = null; + Vector2KeyFrameAnimation hideScaleAnimation = null; + Vector2KeyFrameAnimation showeScaleAnimation = null; + + if (animateOpacity) + { + hideOpacityAnimation = compositor.CreateScalarKeyFrameAnimation(); + hideOpacityAnimation.InsertKeyFrame(1.0f, 0.0f); + hideOpacityAnimation.Duration = TimeSpan.FromMilliseconds(hideDuration); + hideOpacityAnimation.DelayTime = TimeSpan.FromMilliseconds(hideDelay); + hideOpacityAnimation.Target = "Opacity"; + } + + if (!hideToOffset.Equals(0.0f)) + { + hideOffsetAnimation = compositor.CreateScalarKeyFrameAnimation(); + hideOffsetAnimation.InsertKeyFrame(1.0f, hideToOffset); + hideOffsetAnimation.Duration = TimeSpan.FromMilliseconds(hideDuration); + hideOffsetAnimation.DelayTime = TimeSpan.FromMilliseconds(hideDelay); + hideOffsetAnimation.Target = $"Translation.{axis}"; + } + + if (centerPoint.HasValue) + { + elementVisual.CenterPoint = centerPoint.Value; + } + + if (!hideToScale.Equals(1.0f)) + { + hideScaleAnimation = compositor.CreateVector2KeyFrameAnimation(); + hideScaleAnimation.InsertKeyFrame(1.0f, new Vector2(hideToScale)); + hideScaleAnimation.Duration = TimeSpan.FromMilliseconds(hideDuration); + hideScaleAnimation.DelayTime = TimeSpan.FromMilliseconds(hideDelay); + hideScaleAnimation.Target = "Scale.XY"; + } + + var hideAnimationGroup = compositor.CreateAnimationGroup(); + if (hideOpacityAnimation != null) + { + hideAnimationGroup.Add(hideOpacityAnimation); + } + if (hideOffsetAnimation != null) + { + hideAnimationGroup.Add(hideOffsetAnimation); + } + if (hideScaleAnimation != null) + { + hideAnimationGroup.Add(hideScaleAnimation); + } + + ElementCompositionPreview.SetImplicitHideAnimation(element, hideAnimationGroup); + + if (animateOpacity) + { + showOpacityAnimation = compositor.CreateScalarKeyFrameAnimation(); + showOpacityAnimation.InsertKeyFrame(1.0f, 1.0f); + showOpacityAnimation.Duration = TimeSpan.FromMilliseconds(showDuration); + showOpacityAnimation.DelayTime = TimeSpan.FromMilliseconds(showDelay); + showOpacityAnimation.Target = "Opacity"; + } + + if (!showFromOffset.Equals(0.0f)) + { + showOffsetAnimation = compositor.CreateScalarKeyFrameAnimation(); + showOffsetAnimation.InsertKeyFrame(0.0f, showFromOffset); + showOffsetAnimation.InsertKeyFrame(1.0f, 0.0f); + showOffsetAnimation.Duration = TimeSpan.FromMilliseconds(showDuration); + showOffsetAnimation.DelayTime = TimeSpan.FromMilliseconds(showDelay); + showOffsetAnimation.Target = $"Translation.{axis}"; + } + + if (!showFromScale.Equals(1.0f)) + { + showeScaleAnimation = compositor.CreateVector2KeyFrameAnimation(); + showeScaleAnimation.InsertKeyFrame(0.0f, new Vector2(showFromScale)); + showeScaleAnimation.InsertKeyFrame(1.0f, Vector2.One); + showeScaleAnimation.Duration = TimeSpan.FromMilliseconds(showDuration); + showeScaleAnimation.DelayTime = TimeSpan.FromMilliseconds(showDelay); + showeScaleAnimation.Target = "Scale.XY"; + } + + var showAnimationGroup = compositor.CreateAnimationGroup(); + if (showOpacityAnimation != null) + { + showAnimationGroup.Add(showOpacityAnimation); + } + if (showOffsetAnimation != null) + { + showAnimationGroup.Add(showOffsetAnimation); + } + if (showeScaleAnimation != null) + { + showAnimationGroup.Add(showeScaleAnimation); + } + + ElementCompositionPreview.SetImplicitShowAnimation(element, showAnimationGroup); + } + + public static void EnableImplicitAnimation(this UIElement element, VisualPropertyType typeToAnimate, + double duration = 800, double delay = 0, CompositionEasingFunction easing = null) + { + var visual = element.Visual(); + var compositor = visual.Compositor; + + var animationCollection = compositor.CreateImplicitAnimationCollection(); + + foreach (var type in UtilExtensions.GetValues()) + { + if (!typeToAnimate.HasFlag(type)) continue; + + var animation = CreateAnimationByType(compositor, type, duration, delay, easing); + + if (animation != null) + { + animationCollection[type.ToString()] = animation; + } + } + + visual.ImplicitAnimations = animationCollection; + } + + public static void EnableImplicitAnimation(this Visual visual, VisualPropertyType typeToAnimate, + double duration = 800, double delay = 0, CompositionEasingFunction easing = null) + { + var compositor = visual.Compositor; + + var animationCollection = compositor.CreateImplicitAnimationCollection(); + + foreach (var type in UtilExtensions.GetValues()) + { + if (!typeToAnimate.HasFlag(type)) continue; + + var animation = CreateAnimationByType(compositor, type, duration, delay, easing); + + if (animation != null) + { + animationCollection[type.ToString()] = animation; + } + } + + visual.ImplicitAnimations = animationCollection; + } + + private static KeyFrameAnimation CreateAnimationByType(Compositor compositor, VisualPropertyType type, + double duration = 800, double delay = 0, CompositionEasingFunction easing = null) + { + KeyFrameAnimation animation; + + switch (type) + { + case VisualPropertyType.Offset: + case VisualPropertyType.Scale: + animation = compositor.CreateVector3KeyFrameAnimation(); + break; + case VisualPropertyType.Size: + animation = compositor.CreateVector2KeyFrameAnimation(); + break; + case VisualPropertyType.Opacity: + case VisualPropertyType.RotationAngleInDegrees: + animation = compositor.CreateScalarKeyFrameAnimation(); + break; + default: + return null; + } + + animation.InsertExpressionKeyFrame(1.0f, "this.FinalValue", easing); + animation.Duration = TimeSpan.FromMilliseconds(duration); + animation.DelayTime = TimeSpan.FromMilliseconds(delay); + animation.Target = type.ToString(); + + return animation; + } + } +} diff --git a/Wino.Mail.WinUI/Extensions/CompositionExtensions.Size.cs b/Wino.Mail.WinUI/Extensions/CompositionExtensions.Size.cs new file mode 100644 index 00000000..0f634f27 --- /dev/null +++ b/Wino.Mail.WinUI/Extensions/CompositionExtensions.Size.cs @@ -0,0 +1,132 @@ +using System; +using System.Numerics; +using System.Threading.Tasks; + + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Composition; +#else +using Windows.UI.Xaml; +using Windows.UI.Composition; +#endif +namespace Wino.Extensions +{ + public static partial class CompositionExtensions + { + public static void StartSizeAnimation(this UIElement element, Vector2? from = null, Vector2? to = null, + double duration = 800, int delay = 0, CompositionEasingFunction easing = null, Action completed = null, + AnimationIterationBehavior iterationBehavior = AnimationIterationBehavior.Count) + { + CompositionScopedBatch batch = null; + + var visual = element.Visual(); + var compositor = visual.Compositor; + + if (completed != null) + { + batch = compositor.CreateScopedBatch(CompositionBatchTypes.Animation); + batch.Completed += (s, e) => completed(); + } + + if (to == null) + { + to = Vector2.One; + } + + visual.StartAnimation("Size", + compositor.CreateVector2KeyFrameAnimation(from, to.Value, duration, delay, easing, iterationBehavior)); + + batch?.End(); + } + + public static void StartSizeAnimation(this Visual visual, Vector2? from = null, Vector2? to = null, + double duration = 800, int delay = 0, CompositionEasingFunction easing = null, Action completed = null, + AnimationIterationBehavior iterationBehavior = AnimationIterationBehavior.Count) + { + CompositionScopedBatch batch = null; + var compositor = visual.Compositor; + + if (completed != null) + { + batch = compositor.CreateScopedBatch(CompositionBatchTypes.Animation); + batch.Completed += (s, e) => completed(); + } + + if (to == null) + { + to = Vector2.One; + } + visual.StartAnimation("Size", + compositor.CreateVector2KeyFrameAnimation(from, to.Value, duration, delay, easing, iterationBehavior)); + + batch?.End(); + } + + public static Task StartSizeAnimationAsync(this UIElement element, Vector2? from = null, Vector2? to = null, + double duration = 800, int delay = 0, CompositionEasingFunction easing = null, + AnimationIterationBehavior iterationBehavior = AnimationIterationBehavior.Count) + { + CompositionScopedBatch batch; + + var visual = element.Visual(); + var compositor = visual.Compositor; + + var taskSource = new TaskCompletionSource(); + + void Completed(object o, CompositionBatchCompletedEventArgs e) + { + batch.Completed -= Completed; + taskSource.SetResult(true); + } + + batch = compositor.CreateScopedBatch(CompositionBatchTypes.Animation); + batch.Completed += Completed; + + if (to == null) + { + to = Vector2.One; + } + + visual.StartAnimation("Size", + compositor.CreateVector2KeyFrameAnimation(from, to.Value, duration, delay, easing, iterationBehavior)); + + batch.End(); + + return taskSource.Task; + } + + public static Task StartSizeAnimationAsync(this Visual visual, Vector2? from = null, Vector2? to = null, + double duration = 800, int delay = 0, CompositionEasingFunction easing = null, + AnimationIterationBehavior iterationBehavior = AnimationIterationBehavior.Count) + { + CompositionScopedBatch batch; + + var compositor = visual.Compositor; + + var taskSource = new TaskCompletionSource(); + + void Completed(object o, CompositionBatchCompletedEventArgs e) + { + batch.Completed -= Completed; + taskSource.SetResult(true); + } + + batch = compositor.CreateScopedBatch(CompositionBatchTypes.Animation); + batch.Completed += Completed; + + if (to == null) + { + to = Vector2.One; + } + + visual.StartAnimation("Size", + compositor.CreateVector2KeyFrameAnimation(from, to.Value, duration, delay, easing, iterationBehavior)); + + batch.End(); + + return taskSource.Task; + } + + } +} diff --git a/Wino.Mail.WinUI/Extensions/EnumerableExtensions.cs b/Wino.Mail.WinUI/Extensions/EnumerableExtensions.cs new file mode 100644 index 00000000..4d94a9be --- /dev/null +++ b/Wino.Mail.WinUI/Extensions/EnumerableExtensions.cs @@ -0,0 +1,18 @@ +using System.Collections; + +namespace Wino.Extensions +{ + public static class EnumerableExtensions + { + public static IEnumerable OfType(this IEnumerable source) + { + foreach (object item in source) + { + if (item is T1 || item is T2) + { + yield return item; + } + } + } + } +} diff --git a/Wino.Mail.WinUI/Extensions/MimeKitExtensions.cs b/Wino.Mail.WinUI/Extensions/MimeKitExtensions.cs new file mode 100644 index 00000000..d642444f --- /dev/null +++ b/Wino.Mail.WinUI/Extensions/MimeKitExtensions.cs @@ -0,0 +1,19 @@ +using System.Threading.Tasks; +using Windows.Storage; +using Wino.Helpers; +using Wino.Mail.ViewModels.Data; + +namespace Wino.Extensions +{ + public static class MimeKitExtensions + { + public static async Task ToAttachmentViewModelAsync(this StorageFile storageFile) + { + if (storageFile == null) return null; + + var bytes = await storageFile.ReadBytesAsync(); + + return new MailAttachmentViewModel(storageFile.Name, bytes); + } + } +} diff --git a/Wino.Mail.WinUI/Extensions/UIExtensions.cs b/Wino.Mail.WinUI/Extensions/UIExtensions.cs new file mode 100644 index 00000000..65a4723b --- /dev/null +++ b/Wino.Mail.WinUI/Extensions/UIExtensions.cs @@ -0,0 +1,20 @@ +using Microsoft.UI.Xaml.Controls; +using Wino.Core.Domain.Enums; + +namespace Wino.Extensions +{ + public static class UIExtensions + { + public static InfoBarSeverity AsMUXCInfoBarSeverity(this InfoBarMessageType messageType) + { + return messageType switch + { + InfoBarMessageType.Error => InfoBarSeverity.Error, + InfoBarMessageType.Warning => InfoBarSeverity.Warning, + InfoBarMessageType.Information => InfoBarSeverity.Informational, + InfoBarMessageType.Success => InfoBarSeverity.Success, + _ => InfoBarSeverity.Informational + }; + } + } +} diff --git a/Wino.Mail.WinUI/Extensions/UtilExtensions.cs b/Wino.Mail.WinUI/Extensions/UtilExtensions.cs new file mode 100644 index 00000000..807b8db1 --- /dev/null +++ b/Wino.Mail.WinUI/Extensions/UtilExtensions.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Windows.Foundation; + + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Hosting; +using Microsoft.UI.Xaml.Media; +using Microsoft.UI.Composition; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Hosting; +using Windows.UI.Xaml.Media; +using Windows.UI.Composition; +#endif +namespace Wino.Extensions +{ + public static class UtilExtensions + { + public static float ToFloat(this double value) => (float)value; + + public static List Children(this DependencyObject parent) + { + var list = new List(); + + for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) + { + var child = VisualTreeHelper.GetChild(parent, i); + + if (child is FrameworkElement) + { + list.Add(child as FrameworkElement); + } + + list.AddRange(Children(child)); + } + + return list; + } + + public static T GetChildByName(this DependencyObject parent, string name) + { + var childControls = Children(parent); + var controls = childControls.OfType(); + + if (controls == null) + { + return default(T); + } + + var control = controls + .Where(x => x.Name.Equals(name)) + .Cast() + .First(); + + return control; + } + + public static Visual Visual(this UIElement element) => + ElementCompositionPreview.GetElementVisual(element); + + public static void SetChildVisual(this UIElement element, Visual childVisual) => + ElementCompositionPreview.SetElementChildVisual(element, childVisual); + + public static Point RelativePosition(this UIElement element, UIElement other) => + element.TransformToVisual(other).TransformPoint(new Point(0, 0)); + + public static bool IsFullyVisibile(this FrameworkElement element, FrameworkElement parent) + { + if (element == null || parent == null) + return false; + + if (element.Visibility != Visibility.Visible) + return false; + + var elementBounds = element.TransformToVisual(parent).TransformBounds(new Windows.Foundation.Rect(0, 0, element.ActualWidth, element.ActualHeight)); + var containerBounds = new Windows.Foundation.Rect(0, 0, parent.ActualWidth, parent.ActualHeight); + + var originalElementWidth = elementBounds.Width; + var originalElementHeight = elementBounds.Height; + + elementBounds.Intersect(containerBounds); + + var newElementWidth = elementBounds.Width; + var newElementHeight = elementBounds.Height; + + return originalElementWidth.Equals(newElementWidth) && originalElementHeight.Equals(newElementHeight); + } + + public static void ScrollToElement(this ScrollViewer scrollViewer, FrameworkElement element, + bool isVerticalScrolling = true, bool smoothScrolling = true, float? zoomFactor = null, bool bringToTopOrLeft = true) + { + if (!bringToTopOrLeft && element.IsFullyVisibile(scrollViewer)) + return; + + var contentArea = (FrameworkElement)scrollViewer.Content; + var position = element.RelativePosition(contentArea); + + if (isVerticalScrolling) + { + scrollViewer.ChangeView(null, position.Y, zoomFactor, !smoothScrolling); + } + else + { + scrollViewer.ChangeView(position.X, null, zoomFactor, !smoothScrolling); + } + } + + + public static IEnumerable GetValues() => Enum.GetValues(typeof(T)).Cast(); + } +} diff --git a/Wino.Mail.WinUI/Helpers/SettingsStorageExtensions.cs b/Wino.Mail.WinUI/Helpers/SettingsStorageExtensions.cs new file mode 100644 index 00000000..b18fdeeb --- /dev/null +++ b/Wino.Mail.WinUI/Helpers/SettingsStorageExtensions.cs @@ -0,0 +1,31 @@ +using System; +using System.Threading.Tasks; +using Windows.Storage; +using Windows.Storage.Streams; + +namespace Wino.Helpers +{ + // Use these extension methods to store and retrieve local and roaming app data + // More details regarding storing and retrieving app data at https://docs.microsoft.com/windows/uwp/app-settings/store-and-retrieve-app-data + public static class SettingsStorageExtensions + { + public static async Task ReadBytesAsync(this StorageFile file) + { + if (file != null) + { + using (IRandomAccessStream stream = await file.OpenReadAsync()) + { + using (var reader = new DataReader(stream.GetInputStreamAt(0))) + { + await reader.LoadAsync((uint)stream.Size); + var bytes = new byte[stream.Size]; + reader.ReadBytes(bytes); + return bytes; + } + } + } + + return null; + } + } +} diff --git a/Wino.Mail.WinUI/Helpers/WinoVisualTreeHelper.cs b/Wino.Mail.WinUI/Helpers/WinoVisualTreeHelper.cs new file mode 100644 index 00000000..5d47dba5 --- /dev/null +++ b/Wino.Mail.WinUI/Helpers/WinoVisualTreeHelper.cs @@ -0,0 +1,46 @@ + + + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Media; +#else +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Media; +#endif + +namespace Wino.Helpers +{ + public static class WinoVisualTreeHelper + { + public static T GetChildObject(DependencyObject obj, string name) where T : FrameworkElement + { + DependencyObject child = null; + T grandChild = null; + + for (int i = 0; i <= VisualTreeHelper.GetChildrenCount(obj) - 1; i++) + { + child = VisualTreeHelper.GetChild(obj, i); + + if (child is T && (((T)child).Name == name | string.IsNullOrEmpty(name))) + { + return (T)child; + } + else + { + grandChild = GetChildObject(child, name); + } + if (grandChild != null) + { + return grandChild; + } + } + return null; + } + } +} diff --git a/Wino.Mail.WinUI/Helpers/XamlHelpers.cs b/Wino.Mail.WinUI/Helpers/XamlHelpers.cs new file mode 100644 index 00000000..a1c53e1e --- /dev/null +++ b/Wino.Mail.WinUI/Helpers/XamlHelpers.cs @@ -0,0 +1,408 @@ +using System; +using System.Linq; +using Microsoft.UI.Xaml.Controls; + +using Wino.Controls; +using Wino.Core.Domain; +using Wino.Core.Domain.Enums; +using Wino.Core.Domain.Models.MailItem; +using Wino.Core.Domain.Models.Reader; +using Windows.UI.Text; + +#if NET8_0 +using Microsoft.UI; +using Microsoft.UI.Text; +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Markup; +using Microsoft.UI.Xaml.Media; +using CommunityToolkit.WinUI.Helpers; +using Microsoft.UI.Xaml.Shapes; +#else +using Windows.UI; +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Markup; +using Windows.UI.Xaml.Media; +using Microsoft.Toolkit.Uwp.Helpers; +using Windows.UI.Xaml.Shapes; +#endif + +namespace Wino.Helpers +{ + public static class XamlHelpers + { + private const string TwentyFourHourTimeFormat = "HH:mm"; + private const string TwelveHourTimeFormat = "hh:mm tt"; + #region Converters + + public static Visibility ReverseBoolToVisibilityConverter(bool value) => value ? Visibility.Collapsed : Visibility.Visible; + public static Visibility ReverseVisibilityConverter(Visibility visibility) => visibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible; + public static bool ReverseBoolConverter(bool value) => !value; + public static bool ShouldDisplayPreview(string text) => text.Any(x => char.IsLetter(x)); + public static bool CountToBooleanConverter(int value) => value > 0; + public static bool ObjectEquals(object obj1, object obj2) => object.Equals(obj1, obj2); + public static Visibility CountToVisibilityConverter(int value) => value > 0 ? Visibility.Visible : Visibility.Collapsed; + public static InfoBarSeverity InfoBarSeverityConverter(InfoBarMessageType messageType) + { + switch (messageType) + { + case InfoBarMessageType.Information: + return InfoBarSeverity.Informational; + case InfoBarMessageType.Success: + return InfoBarSeverity.Success; + case InfoBarMessageType.Warning: + return InfoBarSeverity.Warning; + case InfoBarMessageType.Error: + return InfoBarSeverity.Error; + default: + return InfoBarSeverity.Informational; + } + } + public static SolidColorBrush GetSolidColorBrushFromHex(string colorHex) => string.IsNullOrEmpty(colorHex) ? new SolidColorBrush(Colors.Transparent) : new SolidColorBrush(colorHex.ToColor()); + public static Visibility IsSelectionModeMultiple(ListViewSelectionMode mode) => mode == ListViewSelectionMode.Multiple ? Visibility.Visible : Visibility.Collapsed; + public static FontWeight GetFontWeightBySyncState(bool isSyncing) => isSyncing ? FontWeights.SemiBold : FontWeights.Normal; + public static FontWeight GetFontWeightByChildSelectedState(bool isChildSelected) => isChildSelected ? FontWeights.SemiBold : FontWeights.Normal; + public static Geometry GetPathIcon(string resourceName) => GetPathGeometry(Application.Current.Resources[$"{resourceName}"] as string); + public static GridLength GetGridLength(double width) => new GridLength(width, GridUnitType.Pixel); + public static double MailListAdaptivityConverter(double mailListPaneLength) => mailListPaneLength + 300d; + public static string GetMailItemDisplaySummaryForListing(bool isDraft, DateTime receivedDate, bool prefer24HourTime) + { + if (isDraft) + return Translator.Draft; + else + { + var localTime = receivedDate.ToLocalTime(); + + return prefer24HourTime ? localTime.ToString(TwentyFourHourTimeFormat) : localTime.ToString(TwelveHourTimeFormat); + } + } + + public static string GetCreationDateString(DateTime date, bool prefer24HourTime) + { + var localTime = date.ToLocalTime(); + return $"{localTime.ToLongDateString()} {(prefer24HourTime ? localTime.ToString(TwentyFourHourTimeFormat) : localTime.ToString(TwelveHourTimeFormat))}"; + } + + public static string GetMailGroupDateString(object groupObject) + { + if (groupObject is string stringObject) + return stringObject; + + object dateObject = null; + + // From regular mail header template + if (groupObject is DateTime groupedDate) + dateObject = groupedDate; + else if (groupObject is IGrouping groupKey) + { + // From semantic group header. + dateObject = groupKey.Key; + } + + if (dateObject != null) + { + if (dateObject is DateTime dateTimeValue) + { + if (dateTimeValue == DateTime.Today) + return Translator.Today; + else if (dateTimeValue == DateTime.Today.AddDays(-1)) + return Translator.Yesterday; + else + return dateTimeValue.ToLongDateString(); + } + else + return dateObject.ToString(); + } + + return Translator.UnknownDateHeader; + } + + #endregion + + #region Wino Font Icon Transformation + + public static WinoIconGlyph GetWinoIconGlyph(FilterOptionType type) => type switch + { + FilterOptionType.All => WinoIconGlyph.SpecialFolderCategory, + FilterOptionType.Unread => WinoIconGlyph.MarkUnread, + FilterOptionType.Flagged => WinoIconGlyph.Flag, + FilterOptionType.Mentions => WinoIconGlyph.NewMail, + // TODO: Attachments icon should be added to WinoIcons.ttf. + FilterOptionType.Files => WinoIconGlyph.None, + _ => WinoIconGlyph.None, + }; + + public static WinoIconGlyph GetWinoIconGlyph(MailOperation operation) + { + switch (operation) + { + case MailOperation.None: + return WinoIconGlyph.None; + case MailOperation.Archive: + return WinoIconGlyph.Archive; + case MailOperation.UnArchive: + return WinoIconGlyph.UnArchive; + case MailOperation.SoftDelete: + case MailOperation.HardDelete: + return WinoIconGlyph.Delete; + case MailOperation.Move: + return WinoIconGlyph.Forward; + case MailOperation.MoveToJunk: + return WinoIconGlyph.Junk; + case MailOperation.MoveToFocused: + break; + case MailOperation.MoveToOther: + break; + case MailOperation.AlwaysMoveToOther: + break; + case MailOperation.AlwaysMoveToFocused: + break; + case MailOperation.SetFlag: + return WinoIconGlyph.Flag; + case MailOperation.ClearFlag: + return WinoIconGlyph.ClearFlag; + case MailOperation.MarkAsRead: + return WinoIconGlyph.MarkRead; + case MailOperation.MarkAsUnread: + return WinoIconGlyph.MarkUnread; + case MailOperation.MarkAsNotJunk: + return WinoIconGlyph.Junk; + case MailOperation.Ignore: + return WinoIconGlyph.Ignore; + case MailOperation.Reply: + return WinoIconGlyph.Reply; + case MailOperation.ReplyAll: + return WinoIconGlyph.ReplyAll; + case MailOperation.Zoom: + return WinoIconGlyph.Zoom; + case MailOperation.SaveAs: + return WinoIconGlyph.Save; + case MailOperation.Find: + return WinoIconGlyph.Find; + case MailOperation.Forward: + return WinoIconGlyph.Forward; + case MailOperation.DarkEditor: + return WinoIconGlyph.DarkEditor; + case MailOperation.LightEditor: + return WinoIconGlyph.LightEditor; + } + + return WinoIconGlyph.None; + } + + public static WinoIconGlyph GetPathGeometry(FolderOperation operation) + { + switch (operation) + { + case FolderOperation.None: + return WinoIconGlyph.None; + case FolderOperation.Pin: + return WinoIconGlyph.Pin; + case FolderOperation.Unpin: + return WinoIconGlyph.UnPin; + case FolderOperation.MarkAllAsRead: + return WinoIconGlyph.MarkRead; + case FolderOperation.DontSync: + return WinoIconGlyph.DontSync; + case FolderOperation.Empty: + return WinoIconGlyph.EmptyFolder; + case FolderOperation.Rename: + return WinoIconGlyph.Rename; + case FolderOperation.Delete: + return WinoIconGlyph.Delete; + case FolderOperation.Move: + return WinoIconGlyph.Forward; + case FolderOperation.TurnOffNotifications: + return WinoIconGlyph.TurnOfNotifications; + case FolderOperation.CreateSubFolder: + return WinoIconGlyph.CreateFolder; + } + + return WinoIconGlyph.None; + } + + public static WinoIconGlyph GetSpecialFolderPathIconGeometry(SpecialFolderType specialFolderType) + { + switch (specialFolderType) + { + case SpecialFolderType.Inbox: + return WinoIconGlyph.SpecialFolderInbox; + case SpecialFolderType.Starred: + return WinoIconGlyph.SpecialFolderStarred; + case SpecialFolderType.Important: + return WinoIconGlyph.SpecialFolderImportant; + case SpecialFolderType.Sent: + return WinoIconGlyph.SpecialFolderSent; + case SpecialFolderType.Draft: + return WinoIconGlyph.SpecialFolderDraft; + case SpecialFolderType.Archive: + return WinoIconGlyph.SpecialFolderArchive; + case SpecialFolderType.Deleted: + return WinoIconGlyph.SpecialFolderDeleted; + case SpecialFolderType.Junk: + return WinoIconGlyph.SpecialFolderJunk; + case SpecialFolderType.Chat: + return WinoIconGlyph.SpecialFolderChat; + case SpecialFolderType.Category: + return WinoIconGlyph.SpecialFolderCategory; + case SpecialFolderType.Unread: + return WinoIconGlyph.SpecialFolderUnread; + case SpecialFolderType.Forums: + return WinoIconGlyph.SpecialFolderForums; + case SpecialFolderType.Updates: + return WinoIconGlyph.SpecialFolderUpdated; + case SpecialFolderType.Personal: + return WinoIconGlyph.SpecialFolderPersonal; + case SpecialFolderType.Promotions: + return WinoIconGlyph.SpecialFolderPromotions; + case SpecialFolderType.Social: + return WinoIconGlyph.SpecialFolderSocial; + case SpecialFolderType.Other: + return WinoIconGlyph.SpecialFolderOther; + case SpecialFolderType.More: + return WinoIconGlyph.SpecialFolderMore; + } + + return WinoIconGlyph.None; + } + + public static WinoIconGlyph GetProviderIcon(MailProviderType providerType) + { + switch (providerType) + { + case MailProviderType.Outlook: + return WinoIconGlyph.Microsoft; + case MailProviderType.Gmail: + return WinoIconGlyph.Google; + case MailProviderType.Office365: + return WinoIconGlyph.Microsoft; + case MailProviderType.IMAP4: + return WinoIconGlyph.Mail; + } + + return WinoIconGlyph.None; + } + + public static Geometry GetPathGeometry(string pathMarkup) + { + string xaml = + "" + + "" + pathMarkup + ""; + var path = XamlReader.Load(xaml) as Path; + + Geometry geometry = path.Data; + path.Data = null; + return geometry; + } + + #endregion + + #region Toolbar Section Initialization + + public static Visibility IsFormatSection(EditorToolbarSection section) => section?.SectionType == EditorToolbarSectionType.Format ? Visibility.Visible : Visibility.Collapsed; + public static Visibility IsInsertSection(EditorToolbarSection section) => section?.SectionType == EditorToolbarSectionType.Insert ? Visibility.Visible : Visibility.Collapsed; + public static Visibility IsDrawSection(EditorToolbarSection section) => section?.SectionType == EditorToolbarSectionType.Draw ? Visibility.Visible : Visibility.Collapsed; + public static Visibility IsOptionsSection(EditorToolbarSection section) => section?.SectionType == EditorToolbarSectionType.Options ? Visibility.Visible : Visibility.Collapsed; + + #endregion + + #region Internationalization + + public static string GetOperationString(MailOperation operation) + { + switch (operation) + { + case MailOperation.None: + return "unknown"; + case MailOperation.Archive: + return Translator.MailOperation_Archive; + case MailOperation.UnArchive: + return Translator.MailOperation_Unarchive; + case MailOperation.SoftDelete: + return Translator.MailOperation_Delete; + case MailOperation.HardDelete: + return Translator.MailOperation_Delete; + case MailOperation.Move: + return Translator.MailOperation_Move; + case MailOperation.MoveToJunk: + return Translator.MailOperation_MoveJunk; + case MailOperation.MoveToFocused: + return Translator.MailOperation_MoveFocused; + case MailOperation.MoveToOther: + return Translator.MailOperation_MoveOther; + case MailOperation.AlwaysMoveToOther: + return Translator.MailOperation_AlwaysMoveOther; + case MailOperation.AlwaysMoveToFocused: + return Translator.MailOperation_AlwaysMoveFocused; + case MailOperation.SetFlag: + return Translator.MailOperation_SetFlag; + case MailOperation.ClearFlag: + return Translator.MailOperation_ClearFlag; + case MailOperation.MarkAsRead: + return Translator.MailOperation_MarkAsRead; + case MailOperation.MarkAsUnread: + return Translator.MailOperation_MarkAsUnread; + case MailOperation.MarkAsNotJunk: + return Translator.MailOperation_MarkNotJunk; + case MailOperation.Seperator: + return string.Empty; + case MailOperation.Ignore: + return Translator.MailOperation_Ignore; + case MailOperation.Reply: + return Translator.MailOperation_Reply; + case MailOperation.ReplyAll: + return Translator.MailOperation_ReplyAll; + case MailOperation.Zoom: + return Translator.MailOperation_Zoom; + case MailOperation.SaveAs: + return Translator.MailOperation_SaveAs; + case MailOperation.Find: + return Translator.MailOperation_Find; + case MailOperation.Forward: + return Translator.MailOperation_Forward; + case MailOperation.DarkEditor: + return string.Empty; + case MailOperation.LightEditor: + return string.Empty; + case MailOperation.Print: + return Translator.MailOperation_Print; + case MailOperation.Navigate: + return Translator.MailOperation_Navigate; + default: + return "unknown"; + } + } + + public static string GetOperationString(FolderOperation operation) + { + switch (operation) + { + case FolderOperation.None: + break; + case FolderOperation.Pin: + return Translator.FolderOperation_Pin; + case FolderOperation.Unpin: + return Translator.FolderOperation_Unpin; + case FolderOperation.MarkAllAsRead: + return Translator.FolderOperation_MarkAllAsRead; + case FolderOperation.DontSync: + return Translator.FolderOperation_DontSync; + case FolderOperation.Empty: + return Translator.FolderOperation_Empty; + case FolderOperation.Rename: + return Translator.FolderOperation_Rename; + case FolderOperation.Delete: + return Translator.FolderOperation_Delete; + case FolderOperation.Move: + return Translator.FolderOperation_Move; + case FolderOperation.CreateSubFolder: + return Translator.FolderOperation_CreateSubFolder; + } + + return string.Empty; + } + + #endregion + } +} diff --git a/Wino.Mail.WinUI/JS/editor.html b/Wino.Mail.WinUI/JS/editor.html new file mode 100644 index 00000000..8ab08aca --- /dev/null +++ b/Wino.Mail.WinUI/JS/editor.html @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wino.Mail.WinUI/JS/editor.js b/Wino.Mail.WinUI/JS/editor.js new file mode 100644 index 00000000..280cb5cc --- /dev/null +++ b/Wino.Mail.WinUI/JS/editor.js @@ -0,0 +1,105 @@ +const editor = Jodit.make("#editor", { + "useSearch": false, + "toolbar": true, + "buttons": "bold,italic,underline,strikethrough,brush,ul,ol,font,fontsize,paragraph,image,link,indent,outdent,align,lineHeight,table", + "inline": true, + "toolbarAdaptive": false, + "toolbarInlineForSelection": false, + "showCharsCounter": false, + style: { font: "14px Arial" }, + "showWordsCounter": false, + "showXPathInStatusbar": false, + "disablePlugins": "add-new-line", + "showPlaceholder": false, + "uploader": { + "insertImageAsBase64URI": true + }, + "enter": "DIV", + "minHeight": 200 +}); + +// Handle the image input change event +imageInput.addEventListener('change', () => { + const file = imageInput.files[0]; + if (file) { + const reader = new FileReader(); + reader.onload = function (event) { + const base64Image = event.target.result; + insertImages([base64Image]); + }; + reader.readAsDataURL(file); + } +}); + +const disabledButtons = ["indent", "outdent"]; +const ariaPressedButtons = ["bold", "italic", "underline", "strikethrough", "ul", "ol"]; + +const alignmentButton = document.querySelector(`[ref='left']`).firstChild.firstChild; +const alignmentObserver = new MutationObserver(function () { + const value = alignmentButton.firstChild.getAttribute('class').split(' ')[0]; + window.chrome.webview.postMessage({ type: 'alignment', value: value }); +}); +alignmentObserver.observe(alignmentButton, { childList: true, attributes: true, attributeFilter: ["class"] }); + +const ariaObservers = ariaPressedButtons.map(button => { + const buttonContainer = document.querySelector(`[ref='${button}']`); + const observer = new MutationObserver(function () { pressedChanged(buttonContainer) }); + observer.observe(buttonContainer.firstChild, { attributes: true, attributeFilter: ["aria-pressed"] }); + + return observer; +}); + +const disabledObservers = disabledButtons.map(button => { + const buttonContainer = document.querySelector(`[ref='${button}']`); + const observer = new MutationObserver(function () { disabledButtonChanged(buttonContainer) }); + observer.observe(buttonContainer.firstChild, { attributes: true, attributeFilter: ["disabled"] }); + + return observer; +}); + +function pressedChanged(buttonContainer) { + const ref = buttonContainer.getAttribute('ref'); + const value = buttonContainer.firstChild.getAttribute('aria-pressed'); + window.chrome.webview.postMessage({ type: ref, value: value }); +} + +function disabledButtonChanged(buttonContainer) { + const ref = buttonContainer.getAttribute('ref'); + const value = buttonContainer.firstChild.getAttribute('disabled'); + console.log(buttonContainer, ref, value); + window.chrome.webview.postMessage({ type: ref, value: value }); +} + + +function RenderHTML(htmlString) { + editor.s.insertHTML(htmlString); + editor.synchronizeValues(); +} + +function GetHTMLContent() { + return editor.value; +} + +function SetLightEditor() { + DarkReader.disable(); +} + +function SetDarkEditor() { + DarkReader.enable(); +} + +function toggleToolbar(enable) { + const toolbar = document.querySelector('.jodit-toolbar__box'); + if (enable == 'true') { + toolbar.style.display = 'flex'; + } + else { + toolbar.style.display = 'none'; + } +} + +function insertImages(images) { + images.forEach(image => { + editor.selection.insertHTML(`Embedded Image`); + }); +}; diff --git a/Wino.Mail.WinUI/JS/global.css b/Wino.Mail.WinUI/JS/global.css new file mode 100644 index 00000000..c20569f5 --- /dev/null +++ b/Wino.Mail.WinUI/JS/global.css @@ -0,0 +1,4 @@ +* { + scrollbar-color: auto !important; + scrollbar-width: thin !important; +} diff --git a/Wino.Mail.WinUI/JS/libs/darkreader.js b/Wino.Mail.WinUI/JS/libs/darkreader.js new file mode 100644 index 00000000..6e45c600 --- /dev/null +++ b/Wino.Mail.WinUI/JS/libs/darkreader.js @@ -0,0 +1,3187 @@ +/** + * Dark Reader v4.9.1 + * https://darkreader.org/ + */ + +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define(['exports'], factory) : + (global = global || self, factory(global.DarkReader = {})); +}(this, (function (exports) { 'use strict'; + + /*! ***************************************************************************** + Copyright (c) Microsoft Corporation. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); you may not use + this file except in compliance with the License. You may obtain a copy of the + License at http://www.apache.org/licenses/LICENSE-2.0 + + THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED + WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, + MERCHANTABLITY OR NON-INFRINGEMENT. + + See the Apache Version 2.0 License for specific language governing permissions + and limitations under the License. + ***************************************************************************** */ + + var __assign = function() { + __assign = Object.assign || function __assign(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); + }; + + function __awaiter(thisArg, _arguments, P, generator) { + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); + } + + function __generator(thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } + } + + function isFirefox() { + return navigator.userAgent.includes('Firefox'); + } + function isMacOS() { + return navigator.platform.toLowerCase().startsWith('mac'); + } + function isDeepSelectorSupported() { + try { + document.querySelector('x /deep/ x'); + return true; + } + catch (err) { + return false; + } + } + function isHostSelectorSupported() { + try { + document.querySelector(':host x'); + return true; + } + catch (err) { + return false; + } + } + function isDefinedSelectorSupported() { + try { + document.querySelector(':defined'); + return true; + } + catch (err) { + return false; + } + } + + function getOKResponse(url, mimeType) { + return __awaiter(this, void 0, void 0, function () { + var response; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4, fetch(url, { + cache: 'force-cache', + credentials: 'omit', + })]; + case 1: + response = _a.sent(); + if (isFirefox() && mimeType === 'text/css' && url.startsWith('moz-extension://') && url.endsWith('.css')) { + return [2, response]; + } + if (mimeType && !response.headers.get('Content-Type').startsWith(mimeType)) { + throw new Error("Mime type mismatch when loading " + url); + } + if (!response.ok) { + throw new Error("Unable to load " + url + " " + response.status + " " + response.statusText); + } + return [2, response]; + } + }); + }); + } + function loadAsDataURL(url, mimeType) { + return __awaiter(this, void 0, void 0, function () { + var response; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4, getOKResponse(url, mimeType)]; + case 1: + response = _a.sent(); + return [4, readResponseAsDataURL(response)]; + case 2: return [2, _a.sent()]; + } + }); + }); + } + function readResponseAsDataURL(response) { + return __awaiter(this, void 0, void 0, function () { + var blob, dataURL; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4, response.blob()]; + case 1: + blob = _a.sent(); + return [4, (new Promise(function (resolve) { + var reader = new FileReader(); + reader.onloadend = function () { return resolve(reader.result); }; + reader.readAsDataURL(blob); + }))]; + case 2: + dataURL = _a.sent(); + return [2, dataURL]; + } + }); + }); + } + + var throwCORSError = function (url) { return __awaiter(void 0, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2, Promise.reject(new Error([ + 'Embedded Dark Reader cannot access a cross-origin resource', + url, + 'Overview your URLs and CORS policies or use', + '`DarkReader.setFetchMethod(fetch: (url) => Promise))`.', + 'See if using `DarkReader.setFetchMethod(window.fetch)`', + 'before `DarkReader.enable()` works.' + ].join(' ')))]; + }); + }); }; + var fetcher = throwCORSError; + function setFetchMethod(fetch) { + if (fetch) { + fetcher = fetch; + } + else { + fetcher = throwCORSError; + } + } + function callFetchMethod(url) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4, fetcher(url)]; + case 1: return [2, _a.sent()]; + } + }); + }); + } + + if (!window.chrome) { + window.chrome = {}; + } + if (!chrome.runtime) { + chrome.runtime = {}; + } + var messageListeners = new Set(); + function sendMessage() { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + return __awaiter(this, void 0, void 0, function () { + var id_1, _a, url, responseType, response, text_1, error_1; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + if (!(args[0] && args[0].type === 'fetch')) return [3, 8]; + id_1 = args[0].id; + _b.label = 1; + case 1: + _b.trys.push([1, 7, , 8]); + _a = args[0].data, url = _a.url, responseType = _a.responseType; + return [4, callFetchMethod(url)]; + case 2: + response = _b.sent(); + if (!(responseType === 'data-url')) return [3, 4]; + return [4, readResponseAsDataURL(response)]; + case 3: + text_1 = _b.sent(); + return [3, 6]; + case 4: return [4, response.text()]; + case 5: + text_1 = _b.sent(); + _b.label = 6; + case 6: + messageListeners.forEach(function (cb) { return cb({ type: 'fetch-response', data: text_1, error: null, id: id_1 }); }); + return [3, 8]; + case 7: + error_1 = _b.sent(); + console.error(error_1); + messageListeners.forEach(function (cb) { return cb({ type: 'fetch-response', data: null, error: error_1, id: id_1 }); }); + return [3, 8]; + case 8: return [2]; + } + }); + }); + } + function addMessageListener(callback) { + messageListeners.add(callback); + } + if (typeof chrome.runtime.sendMessage === 'function') { + var nativeSendMessage_1 = chrome.runtime.sendMessage; + chrome.runtime.sendMessage = function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + sendMessage.apply(void 0, args); + nativeSendMessage_1.apply(chrome.runtime, args); + }; + } + else { + chrome.runtime.sendMessage = sendMessage; + } + if (!chrome.runtime.onMessage) { + chrome.runtime.onMessage = {}; + } + if (typeof chrome.runtime.onMessage.addListener === 'function') { + var nativeAddListener_1 = chrome.runtime.onMessage.addListener; + chrome.runtime.onMessage.addListener = function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + addMessageListener.apply(void 0, args); + nativeAddListener_1.apply(chrome.runtime.onMessage, args); + }; + } + else { + chrome.runtime.onMessage.addListener = addMessageListener; + } + + var ThemeEngines = { + cssFilter: 'cssFilter', + svgFilter: 'svgFilter', + staticTheme: 'staticTheme', + dynamicTheme: 'dynamicTheme', + }; + + function parseURL(url) { + var a = document.createElement('a'); + a.href = url; + return a; + } + function getAbsoluteURL($base, $relative) { + if ($relative.match(/^.*?\/\//) || $relative.match(/^data\:/)) { + if ($relative.startsWith('//')) { + return "" + location.protocol + $relative; + } + return $relative; + } + var b = parseURL($base); + if ($relative.startsWith('/')) { + var u_1 = parseURL(b.protocol + "//" + b.host + $relative); + return u_1.href; + } + var pathParts = b.pathname.split('/').concat($relative.split('/')).filter(function (p) { return p; }); + var backwardIndex; + while ((backwardIndex = pathParts.indexOf('..')) > 0) { + pathParts.splice(backwardIndex - 1, 2); + } + var u = parseURL(b.protocol + "//" + b.host + "/" + pathParts.join('/')); + return u.href; + } + + function logInfo() { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + } + function logWarn() { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + } + + function iterateCSSRules(rules, iterate) { + Array.from(rules) + .forEach(function (rule) { + if (rule instanceof CSSMediaRule) { + var media = Array.from(rule.media); + if (media.includes('screen') || media.includes('all') || !(media.includes('print') || media.includes('speech'))) { + iterateCSSRules(rule.cssRules, iterate); + } + } + else if (rule instanceof CSSStyleRule) { + iterate(rule); + } + else if (rule instanceof CSSImportRule) { + try { + iterateCSSRules(rule.styleSheet.cssRules, iterate); + } + catch (err) { + logWarn(err); + } + } + else { + logWarn("CSSRule type not supported", rule); + } + }); + } + function iterateCSSDeclarations(style, iterate) { + Array.from(style).forEach(function (property) { + var value = style.getPropertyValue(property).trim(); + if (!value) { + return; + } + iterate(property, value); + }); + } + function isCSSVariable(property) { + return property.startsWith('--') && !property.startsWith('--darkreader'); + } + function getCSSVariables(rules) { + var variables = new Map(); + rules && iterateCSSRules(rules, function (rule) { + rule.style && iterateCSSDeclarations(rule.style, function (property, value) { + if (isCSSVariable(property)) { + variables.set(property, value); + } + }); + }); + return variables; + } + function getElementCSSVariables(element) { + var variables = new Map(); + iterateCSSDeclarations(element.style, function (property, value) { + if (isCSSVariable(property)) { + variables.set(property, value); + } + }); + return variables; + } + var cssURLRegex = /url\((('.+?')|(".+?")|([^\)]*?))\)/g; + var cssImportRegex = /@import (url\()?(('.+?')|(".+?")|([^\)]*?))\)?;?/g; + function getCSSURLValue(cssURL) { + return cssURL.replace(/^url\((.*)\)$/, '$1').replace(/^"(.*)"$/, '$1').replace(/^'(.*)'$/, '$1'); + } + function getCSSBaseBath(url) { + var cssURL = parseURL(url); + return cssURL.protocol + "//" + cssURL.host + cssURL.pathname.replace(/\?.*$/, '').replace(/(\/)([^\/]+)$/i, '$1'); + } + function replaceCSSRelativeURLsWithAbsolute($css, cssBasePath) { + return $css.replace(cssURLRegex, function (match) { + var pathValue = getCSSURLValue(match); + return "url(\"" + getAbsoluteURL(cssBasePath, pathValue) + "\")"; + }); + } + var cssCommentsRegex = /\/\*[\s\S]*?\*\//g; + function removeCSSComments($css) { + return $css.replace(cssCommentsRegex, ''); + } + var fontFaceRegex = /@font-face\s*{[^}]*}/g; + function replaceCSSFontFace($css) { + return $css.replace(fontFaceRegex, ''); + } + var varRegex = /var\((--[^\s,]+),?\s*([^\(\)]*(\([^\(\)]*\)[^\(\)]*)*\s*)\)/g; + function replaceCSSVariables(value, variables) { + var missing = false; + var result = value.replace(varRegex, function (match, name, fallback) { + if (variables.has(name)) { + return variables.get(name); + } + else if (fallback) { + return fallback; + } + else { + logWarn("Variable " + name + " not found"); + missing = true; + } + return match; + }); + if (missing) { + return result; + } + if (result.match(varRegex)) { + return replaceCSSVariables(result, variables); + } + return result; + } + + function throttle(callback) { + var pending = false; + var frameId = null; + var lastArgs; + var throttled = (function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + lastArgs = args; + if (frameId) { + pending = true; + } + else { + callback.apply(void 0, lastArgs); + frameId = requestAnimationFrame(function () { + frameId = null; + if (pending) { + callback.apply(void 0, lastArgs); + pending = false; + } + }); + } + }); + var cancel = function () { + cancelAnimationFrame(frameId); + pending = false; + frameId = null; + }; + return Object.assign(throttled, { cancel: cancel }); + } + function createAsyncTasksQueue() { + var tasks = []; + var frameId = null; + function runTasks() { + var task; + while (task = tasks.shift()) { + task(); + } + frameId = null; + } + function add(task) { + tasks.push(task); + if (!frameId) { + frameId = requestAnimationFrame(runTasks); + } + } + function cancel() { + tasks.splice(0); + cancelAnimationFrame(frameId); + frameId = null; + } + return { add: add, cancel: cancel }; + } + + function getDuration(time) { + var duration = 0; + if (time.seconds) { + duration += time.seconds * 1000; + } + if (time.minutes) { + duration += time.minutes * 60 * 1000; + } + if (time.hours) { + duration += time.hours * 60 * 60 * 1000; + } + if (time.days) { + duration += time.days * 24 * 60 * 60 * 1000; + } + return duration; + } + + function removeNode(node) { + node && node.parentNode && node.parentNode.removeChild(node); + } + function watchForNodePosition(node, _a) { + var _b = _a.onRestore, onRestore = _b === void 0 ? Function.prototype : _b, _c = _a.watchParent, watchParent = _c === void 0 ? true : _c, _d = _a.watchSibling, watchSibling = _d === void 0 ? false : _d; + var MAX_ATTEMPTS_COUNT = 10; + var ATTEMPTS_INTERVAL = getDuration({ seconds: 10 }); + var prevSibling = node.previousSibling; + var parent = node.parentNode; + if (!parent) { + logWarn('Unable to watch for node position: parent element not found', node, prevSibling); + return { stop: Function.prototype }; + } + var attempts = 0; + var start = null; + var restore = throttle(function () { + attempts++; + var now = Date.now(); + if (start == null) { + start = now; + } + else if (attempts >= MAX_ATTEMPTS_COUNT) { + if (now - start < ATTEMPTS_INTERVAL) { + logWarn('Node position watcher stopped: some script conflicts with Dark Reader and can cause high CPU usage', node, prevSibling); + stop(); + return; + } + start = now; + attempts = 1; + } + if (prevSibling && prevSibling.parentNode !== parent) { + logWarn('Unable to restore node position: sibling was removed', node, prevSibling, parent); + stop(); + return; + } + logWarn('Node was removed, restoring it\'s position', node, prevSibling, parent); + parent.insertBefore(node, prevSibling ? prevSibling.nextSibling : parent.firstChild); + onRestore && onRestore(); + }); + var observer = new MutationObserver(function () { + if ((watchParent && !node.parentNode) || + (watchSibling && node.previousSibling !== prevSibling)) { + restore(); + observer.takeRecords(); + } + }); + var run = function () { + observer.observe(parent, { childList: true }); + }; + var stop = function () { + observer.disconnect(); + }; + run(); + return { run: run, stop: stop }; + } + function iterateShadowNodes(root, iterator) { + var walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, { + acceptNode: function (node) { + return node.shadowRoot == null ? NodeFilter.FILTER_SKIP : NodeFilter.FILTER_ACCEPT; + } + }, false); + for (var node = (root.shadowRoot ? walker.currentNode : walker.nextNode()); node != null; node = walker.nextNode()) { + iterator(node); + iterateShadowNodes(node.shadowRoot, iterator); + } + } + + function hslToRGB(_a) { + var h = _a.h, s = _a.s, l = _a.l, _b = _a.a, a = _b === void 0 ? 1 : _b; + if (s === 0) { + var _c = [l, l, l].map(function (x) { return Math.round(x * 255); }), r_1 = _c[0], b_1 = _c[1], g_1 = _c[2]; + return { r: r_1, g: g_1, b: b_1, a: a }; + } + var c = (1 - Math.abs(2 * l - 1)) * s; + var x = c * (1 - Math.abs((h / 60) % 2 - 1)); + var m = l - c / 2; + var _d = (h < 60 ? [c, x, 0] : + h < 120 ? [x, c, 0] : + h < 180 ? [0, c, x] : + h < 240 ? [0, x, c] : + h < 300 ? [x, 0, c] : + [c, 0, x]).map(function (n) { return Math.round((n + m) * 255); }), r = _d[0], g = _d[1], b = _d[2]; + return { r: r, g: g, b: b, a: a }; + } + function rgbToHSL(_a) { + var r255 = _a.r, g255 = _a.g, b255 = _a.b, _b = _a.a, a = _b === void 0 ? 1 : _b; + var r = r255 / 255; + var g = g255 / 255; + var b = b255 / 255; + var max = Math.max(r, g, b); + var min = Math.min(r, g, b); + var c = max - min; + var l = (max + min) / 2; + if (c === 0) { + return { h: 0, s: 0, l: l, a: a }; + } + var h = (max === r ? (((g - b) / c) % 6) : + max === g ? ((b - r) / c + 2) : + ((r - g) / c + 4)) * 60; + if (h < 0) { + h += 360; + } + var s = c / (1 - Math.abs(2 * l - 1)); + return { h: h, s: s, l: l, a: a }; + } + function toFixed(n, digits) { + if (digits === void 0) { digits = 0; } + var fixed = n.toFixed(digits); + if (digits === 0) { + return fixed; + } + var dot = fixed.indexOf('.'); + if (dot >= 0) { + var zerosMatch = fixed.match(/0+$/); + if (zerosMatch) { + if (zerosMatch.index === dot + 1) { + return fixed.substring(0, dot); + } + return fixed.substring(0, zerosMatch.index); + } + } + return fixed; + } + function rgbToString(rgb) { + var r = rgb.r, g = rgb.g, b = rgb.b, a = rgb.a; + if (a != null && a < 1) { + return "rgba(" + toFixed(r) + ", " + toFixed(g) + ", " + toFixed(b) + ", " + toFixed(a, 2) + ")"; + } + return "rgb(" + toFixed(r) + ", " + toFixed(g) + ", " + toFixed(b) + ")"; + } + function rgbToHexString(_a) { + var r = _a.r, g = _a.g, b = _a.b, a = _a.a; + return "#" + (a != null && a < 1 ? [r, g, b, Math.round(a * 255)] : [r, g, b]).map(function (x) { + return "" + (x < 16 ? '0' : '') + x.toString(16); + }).join(''); + } + var rgbMatch = /^rgba?\([^\(\)]+\)$/; + var hslMatch = /^hsla?\([^\(\)]+\)$/; + var hexMatch = /^#[0-9a-f]+$/i; + function parse($color) { + var c = $color.trim().toLowerCase(); + if (c.match(rgbMatch)) { + return parseRGB(c); + } + if (c.match(hslMatch)) { + return parseHSL(c); + } + if (c.match(hexMatch)) { + return parseHex(c); + } + if (knownColors.has(c)) { + return getColorByName(c); + } + if (systemColors.has(c)) { + return getSystemColor(c); + } + if ($color === 'transparent') { + return { r: 0, g: 0, b: 0, a: 0 }; + } + throw new Error("Unable to parse " + $color); + } + function getNumbersFromString(str, splitter, range, units) { + var raw = str.split(splitter).filter(function (x) { return x; }); + var unitsList = Object.entries(units); + var numbers = raw.map(function (r) { return r.trim(); }).map(function (r, i) { + var n; + var unit = unitsList.find(function (_a) { + var u = _a[0]; + return r.endsWith(u); + }); + if (unit) { + n = parseFloat(r.substring(0, r.length - unit[0].length)) / unit[1] * range[i]; + } + else { + n = parseFloat(r); + } + if (range[i] > 1) { + return Math.round(n); + } + return n; + }); + return numbers; + } + var rgbSplitter = /rgba?|\(|\)|\/|,|\s/ig; + var rgbRange = [255, 255, 255, 1]; + var rgbUnits = { '%': 100 }; + function parseRGB($rgb) { + var _a = getNumbersFromString($rgb, rgbSplitter, rgbRange, rgbUnits), r = _a[0], g = _a[1], b = _a[2], _b = _a[3], a = _b === void 0 ? 1 : _b; + return { r: r, g: g, b: b, a: a }; + } + var hslSplitter = /hsla?|\(|\)|\/|,|\s/ig; + var hslRange = [360, 1, 1, 1]; + var hslUnits = { '%': 100, 'deg': 360, 'rad': 2 * Math.PI, 'turn': 1 }; + function parseHSL($hsl) { + var _a = getNumbersFromString($hsl, hslSplitter, hslRange, hslUnits), h = _a[0], s = _a[1], l = _a[2], _b = _a[3], a = _b === void 0 ? 1 : _b; + return hslToRGB({ h: h, s: s, l: l, a: a }); + } + function parseHex($hex) { + var h = $hex.substring(1); + switch (h.length) { + case 3: + case 4: { + var _a = [0, 1, 2].map(function (i) { return parseInt("" + h[i] + h[i], 16); }), r = _a[0], g = _a[1], b = _a[2]; + var a = h.length === 3 ? 1 : (parseInt("" + h[3] + h[3], 16) / 255); + return { r: r, g: g, b: b, a: a }; + } + case 6: + case 8: { + var _b = [0, 2, 4].map(function (i) { return parseInt(h.substring(i, i + 2), 16); }), r = _b[0], g = _b[1], b = _b[2]; + var a = h.length === 6 ? 1 : (parseInt(h.substring(6, 8), 16) / 255); + return { r: r, g: g, b: b, a: a }; + } + } + throw new Error("Unable to parse " + $hex); + } + function getColorByName($color) { + var n = knownColors.get($color); + return { + r: (n >> 16) & 255, + g: (n >> 8) & 255, + b: (n >> 0) & 255, + a: 1 + }; + } + function getSystemColor($color) { + var n = systemColors.get($color); + return { + r: (n >> 16) & 255, + g: (n >> 8) & 255, + b: (n >> 0) & 255, + a: 1 + }; + } + var knownColors = new Map(Object.entries({ + aliceblue: 0xf0f8ff, + antiquewhite: 0xfaebd7, + aqua: 0x00ffff, + aquamarine: 0x7fffd4, + azure: 0xf0ffff, + beige: 0xf5f5dc, + bisque: 0xffe4c4, + black: 0x000000, + blanchedalmond: 0xffebcd, + blue: 0x0000ff, + blueviolet: 0x8a2be2, + brown: 0xa52a2a, + burlywood: 0xdeb887, + cadetblue: 0x5f9ea0, + chartreuse: 0x7fff00, + chocolate: 0xd2691e, + coral: 0xff7f50, + cornflowerblue: 0x6495ed, + cornsilk: 0xfff8dc, + crimson: 0xdc143c, + cyan: 0x00ffff, + darkblue: 0x00008b, + darkcyan: 0x008b8b, + darkgoldenrod: 0xb8860b, + darkgray: 0xa9a9a9, + darkgrey: 0xa9a9a9, + darkgreen: 0x006400, + darkkhaki: 0xbdb76b, + darkmagenta: 0x8b008b, + darkolivegreen: 0x556b2f, + darkorange: 0xff8c00, + darkorchid: 0x9932cc, + darkred: 0x8b0000, + darksalmon: 0xe9967a, + darkseagreen: 0x8fbc8f, + darkslateblue: 0x483d8b, + darkslategray: 0x2f4f4f, + darkslategrey: 0x2f4f4f, + darkturquoise: 0x00ced1, + darkviolet: 0x9400d3, + deeppink: 0xff1493, + deepskyblue: 0x00bfff, + dimgray: 0x696969, + dimgrey: 0x696969, + dodgerblue: 0x1e90ff, + firebrick: 0xb22222, + floralwhite: 0xfffaf0, + forestgreen: 0x228b22, + fuchsia: 0xff00ff, + gainsboro: 0xdcdcdc, + ghostwhite: 0xf8f8ff, + gold: 0xffd700, + goldenrod: 0xdaa520, + gray: 0x808080, + grey: 0x808080, + green: 0x008000, + greenyellow: 0xadff2f, + honeydew: 0xf0fff0, + hotpink: 0xff69b4, + indianred: 0xcd5c5c, + indigo: 0x4b0082, + ivory: 0xfffff0, + khaki: 0xf0e68c, + lavender: 0xe6e6fa, + lavenderblush: 0xfff0f5, + lawngreen: 0x7cfc00, + lemonchiffon: 0xfffacd, + lightblue: 0xadd8e6, + lightcoral: 0xf08080, + lightcyan: 0xe0ffff, + lightgoldenrodyellow: 0xfafad2, + lightgray: 0xd3d3d3, + lightgrey: 0xd3d3d3, + lightgreen: 0x90ee90, + lightpink: 0xffb6c1, + lightsalmon: 0xffa07a, + lightseagreen: 0x20b2aa, + lightskyblue: 0x87cefa, + lightslategray: 0x778899, + lightslategrey: 0x778899, + lightsteelblue: 0xb0c4de, + lightyellow: 0xffffe0, + lime: 0x00ff00, + limegreen: 0x32cd32, + linen: 0xfaf0e6, + magenta: 0xff00ff, + maroon: 0x800000, + mediumaquamarine: 0x66cdaa, + mediumblue: 0x0000cd, + mediumorchid: 0xba55d3, + mediumpurple: 0x9370db, + mediumseagreen: 0x3cb371, + mediumslateblue: 0x7b68ee, + mediumspringgreen: 0x00fa9a, + mediumturquoise: 0x48d1cc, + mediumvioletred: 0xc71585, + midnightblue: 0x191970, + mintcream: 0xf5fffa, + mistyrose: 0xffe4e1, + moccasin: 0xffe4b5, + navajowhite: 0xffdead, + navy: 0x000080, + oldlace: 0xfdf5e6, + olive: 0x808000, + olivedrab: 0x6b8e23, + orange: 0xffa500, + orangered: 0xff4500, + orchid: 0xda70d6, + palegoldenrod: 0xeee8aa, + palegreen: 0x98fb98, + paleturquoise: 0xafeeee, + palevioletred: 0xdb7093, + papayawhip: 0xffefd5, + peachpuff: 0xffdab9, + peru: 0xcd853f, + pink: 0xffc0cb, + plum: 0xdda0dd, + powderblue: 0xb0e0e6, + purple: 0x800080, + rebeccapurple: 0x663399, + red: 0xff0000, + rosybrown: 0xbc8f8f, + royalblue: 0x4169e1, + saddlebrown: 0x8b4513, + salmon: 0xfa8072, + sandybrown: 0xf4a460, + seagreen: 0x2e8b57, + seashell: 0xfff5ee, + sienna: 0xa0522d, + silver: 0xc0c0c0, + skyblue: 0x87ceeb, + slateblue: 0x6a5acd, + slategray: 0x708090, + slategrey: 0x708090, + snow: 0xfffafa, + springgreen: 0x00ff7f, + steelblue: 0x4682b4, + tan: 0xd2b48c, + teal: 0x008080, + thistle: 0xd8bfd8, + tomato: 0xff6347, + turquoise: 0x40e0d0, + violet: 0xee82ee, + wheat: 0xf5deb3, + white: 0xffffff, + whitesmoke: 0xf5f5f5, + yellow: 0xffff00, + yellowgreen: 0x9acd32, + })); + var systemColors = new Map(Object.entries({ + ActiveBorder: 0x3b99fc, + ActiveCaption: 0x000000, + AppWorkspace: 0xaaaaaa, + Background: 0x6363ce, + ButtonFace: 0xffffff, + ButtonHighlight: 0xe9e9e9, + ButtonShadow: 0x9fa09f, + ButtonText: 0x000000, + CaptionText: 0x000000, + GrayText: 0x7f7f7f, + Highlight: 0xb2d7ff, + HighlightText: 0x000000, + InactiveBorder: 0xffffff, + InactiveCaption: 0xffffff, + InactiveCaptionText: 0x000000, + InfoBackground: 0xfbfcc5, + InfoText: 0x000000, + Menu: 0xf6f6f6, + MenuText: 0xffffff, + Scrollbar: 0xaaaaaa, + ThreeDDarkShadow: 0x000000, + ThreeDFace: 0xc0c0c0, + ThreeDHighlight: 0xffffff, + ThreeDLightShadow: 0xffffff, + ThreeDShadow: 0x000000, + Window: 0xececec, + WindowFrame: 0xaaaaaa, + WindowText: 0x000000, + '-webkit-focus-ring-color': 0xe59700 + }).map(function (_a) { + var key = _a[0], value = _a[1]; + return [key.toLowerCase(), value]; + })); + + function scale(x, inLow, inHigh, outLow, outHigh) { + return (x - inLow) * (outHigh - outLow) / (inHigh - inLow) + outLow; + } + function clamp(x, min, max) { + return Math.min(max, Math.max(min, x)); + } + function multiplyMatrices(m1, m2) { + var result = []; + for (var i = 0; i < m1.length; i++) { + result[i] = []; + for (var j = 0; j < m2[0].length; j++) { + var sum = 0; + for (var k = 0; k < m1[0].length; k++) { + sum += m1[i][k] * m2[k][j]; + } + result[i][j] = sum; + } + } + return result; + } + + function getMatches(regex, input, group) { + if (group === void 0) { group = 0; } + var matches = []; + var m; + while (m = regex.exec(input)) { + matches.push(m[group]); + } + return matches; + } + + function createFilterMatrix(config) { + var m = Matrix.identity(); + if (config.sepia !== 0) { + m = multiplyMatrices(m, Matrix.sepia(config.sepia / 100)); + } + if (config.grayscale !== 0) { + m = multiplyMatrices(m, Matrix.grayscale(config.grayscale / 100)); + } + if (config.contrast !== 100) { + m = multiplyMatrices(m, Matrix.contrast(config.contrast / 100)); + } + if (config.brightness !== 100) { + m = multiplyMatrices(m, Matrix.brightness(config.brightness / 100)); + } + if (config.mode === 1) { + m = multiplyMatrices(m, Matrix.invertNHue()); + } + return m; + } + function applyColorMatrix(_a, matrix) { + var r = _a[0], g = _a[1], b = _a[2]; + var rgb = [[r / 255], [g / 255], [b / 255], [1], [1]]; + var result = multiplyMatrices(matrix, rgb); + return [0, 1, 2].map(function (i) { return clamp(Math.round(result[i][0] * 255), 0, 255); }); + } + var Matrix = { + identity: function () { + return [ + [1, 0, 0, 0, 0], + [0, 1, 0, 0, 0], + [0, 0, 1, 0, 0], + [0, 0, 0, 1, 0], + [0, 0, 0, 0, 1] + ]; + }, + invertNHue: function () { + return [ + [0.333, -0.667, -0.667, 0, 1], + [-0.667, 0.333, -0.667, 0, 1], + [-0.667, -0.667, 0.333, 0, 1], + [0, 0, 0, 1, 0], + [0, 0, 0, 0, 1] + ]; + }, + brightness: function (v) { + return [ + [v, 0, 0, 0, 0], + [0, v, 0, 0, 0], + [0, 0, v, 0, 0], + [0, 0, 0, 1, 0], + [0, 0, 0, 0, 1] + ]; + }, + contrast: function (v) { + var t = (1 - v) / 2; + return [ + [v, 0, 0, 0, t], + [0, v, 0, 0, t], + [0, 0, v, 0, t], + [0, 0, 0, 1, 0], + [0, 0, 0, 0, 1] + ]; + }, + sepia: function (v) { + return [ + [(0.393 + 0.607 * (1 - v)), (0.769 - 0.769 * (1 - v)), (0.189 - 0.189 * (1 - v)), 0, 0], + [(0.349 - 0.349 * (1 - v)), (0.686 + 0.314 * (1 - v)), (0.168 - 0.168 * (1 - v)), 0, 0], + [(0.272 - 0.272 * (1 - v)), (0.534 - 0.534 * (1 - v)), (0.131 + 0.869 * (1 - v)), 0, 0], + [0, 0, 0, 1, 0], + [0, 0, 0, 0, 1] + ]; + }, + grayscale: function (v) { + return [ + [(0.2126 + 0.7874 * (1 - v)), (0.7152 - 0.7152 * (1 - v)), (0.0722 - 0.0722 * (1 - v)), 0, 0], + [(0.2126 - 0.2126 * (1 - v)), (0.7152 + 0.2848 * (1 - v)), (0.0722 - 0.0722 * (1 - v)), 0, 0], + [(0.2126 - 0.2126 * (1 - v)), (0.7152 - 0.7152 * (1 - v)), (0.0722 + 0.9278 * (1 - v)), 0, 0], + [0, 0, 0, 1, 0], + [0, 0, 0, 0, 1] + ]; + }, + }; + + var colorModificationCache = new Map(); + function clearColorModificationCache() { + colorModificationCache.clear(); + } + function modifyColorWithCache(rgb, filter, modifyHSL) { + var fnCache; + if (colorModificationCache.has(modifyHSL)) { + fnCache = colorModificationCache.get(modifyHSL); + } + else { + fnCache = new Map(); + colorModificationCache.set(modifyHSL, fnCache); + } + var id = Object.entries(rgb) + .concat(Object.entries(filter).filter(function (_a) { + var key = _a[0]; + return ['mode', 'brightness', 'contrast', 'grayscale', 'sepia'].indexOf(key) >= 0; + })) + .map(function (_a) { + var key = _a[0], value = _a[1]; + return key + ":" + value; + }) + .join(';'); + if (fnCache.has(id)) { + return fnCache.get(id); + } + var hsl = rgbToHSL(rgb); + var modified = modifyHSL(hsl); + var _a = hslToRGB(modified), r = _a.r, g = _a.g, b = _a.b, a = _a.a; + var matrix = createFilterMatrix(filter); + var _b = applyColorMatrix([r, g, b], matrix), rf = _b[0], gf = _b[1], bf = _b[2]; + var color = (a === 1 ? + rgbToHexString({ r: rf, g: gf, b: bf }) : + rgbToString({ r: rf, g: gf, b: bf, a: a })); + fnCache.set(id, color); + return color; + } + function noopHSL(hsl) { + return hsl; + } + function modifyColor(rgb, theme) { + return modifyColorWithCache(rgb, theme, noopHSL); + } + function modifyLightModeHSL(_a) { + var h = _a.h, s = _a.s, l = _a.l, a = _a.a; + var lMin = 0; + var lMid = 0.4; + var lMax = 0.9; + var sNeutralLim = 0.36; + var lNeutralDark = 0.2; + var lNeutralLight = 0.8; + var sColored = 0.16; + var hColoredL0 = 205; + var hColoredL1 = 40; + var lx = scale(l, 0, 1, lMin, lMax); + var hx = h; + var sx = s; + var isNeutral = l < lNeutralDark || l > lNeutralLight || s < sNeutralLim; + if (isNeutral) { + sx = (l < lMid ? + scale(l, 0, lMid, sColored, 0) : + scale(l, lMid, 1, 0, sColored)); + hx = (l < lMid ? hColoredL0 : hColoredL1); + } + return { h: hx, s: sx, l: lx, a: a }; + } + function modifyBgHSL(_a) { + var h = _a.h, s = _a.s, l = _a.l, a = _a.a; + var lMin = 0.1; + var lMaxS0 = 0.25; + var lMaxS1 = 0.4; + var sNeutralLim = 0.12; + var lNeutralLight = 0.8; + var sColored = 0.05; + var hColored = 205; + var hBlue0 = 200; + var hBlue1 = 280; + var lMax = scale(s, 0, 1, lMaxS0, lMaxS1); + var lx = (l < lMax ? + l : + l < 0.5 ? + lMax : + scale(l, 0.5, 1, lMax, lMin)); + var isNeutral = (l >= lNeutralLight && h > hBlue0 && h < hBlue1) || s < sNeutralLim; + var hx = h; + var sx = s; + if (isNeutral) { + sx = sColored; + hx = hColored; + } + return { h: hx, s: sx, l: lx, a: a }; + } + function modifyBackgroundColor(rgb, filter) { + if (filter.mode === 0) { + return modifyColorWithCache(rgb, filter, modifyLightModeHSL); + } + return modifyColorWithCache(rgb, __assign(__assign({}, filter), { mode: 0 }), modifyBgHSL); + } + function modifyFgHSL(_a) { + var h = _a.h, s = _a.s, l = _a.l, a = _a.a; + var lMax = 0.9; + var lMinS0 = 0.7; + var lMinS1 = 0.6; + var sNeutralLim = 0.24; + var lNeutralDark = 0.2; + var sColored = 0.10; + var hColored = 40; + var hBlue0 = 205; + var hBlue1 = 245; + var hBlueMax = 220; + var lBlueMin = 0.7; + var isBlue = h > hBlue0 && h <= hBlue1; + var lMin = scale(s, 0, 1, isBlue ? scale(h, hBlue0, hBlue1, lMinS0, lBlueMin) : lMinS0, lMinS1); + var lx = (l < 0.5 ? + scale(l, 0, 0.5, lMax, lMin) : + l < lMin ? + lMin : + l); + var hx = h; + var sx = s; + if (isBlue) { + hx = scale(hx, hBlue0, hBlue1, hBlue0, hBlueMax); + } + var isNeutral = l < lNeutralDark || s < sNeutralLim; + if (isNeutral) { + sx = sColored; + hx = hColored; + } + return { h: hx, s: sx, l: lx, a: a }; + } + function modifyForegroundColor(rgb, filter) { + if (filter.mode === 0) { + return modifyColorWithCache(rgb, filter, modifyLightModeHSL); + } + return modifyColorWithCache(rgb, __assign(__assign({}, filter), { mode: 0 }), modifyFgHSL); + } + function modifyBorderHSL(_a) { + var h = _a.h, s = _a.s, l = _a.l, a = _a.a; + var lMinS0 = 0.2; + var lMinS1 = 0.3; + var lMaxS0 = 0.4; + var lMaxS1 = 0.5; + var lMin = scale(s, 0, 1, lMinS0, lMinS1); + var lMax = scale(s, 0, 1, lMaxS0, lMaxS1); + var lx = scale(l, 0, 1, lMax, lMin); + return { h: h, s: s, l: lx, a: a }; + } + function modifyBorderColor(rgb, filter) { + if (filter.mode === 0) { + return modifyColorWithCache(rgb, filter, modifyLightModeHSL); + } + return modifyColorWithCache(rgb, __assign(__assign({}, filter), { mode: 0 }), modifyBorderHSL); + } + function modifyShadowColor(rgb, filter) { + return modifyBackgroundColor(rgb, filter); + } + function modifyGradientColor(rgb, filter) { + return modifyBackgroundColor(rgb, filter); + } + + function getURLHost(url) { + return url.match(/^(.*?\/{2,3})?(.+?)(\/|$)/)[2]; + } + + function createTextStyle(config) { + var lines = []; + lines.push('* {'); + if (config.useFont && config.fontFamily) { + lines.push(" font-family: " + config.fontFamily + " !important;"); + } + if (config.textStroke > 0) { + lines.push(" -webkit-text-stroke: " + config.textStroke + "px !important;"); + lines.push(" text-stroke: " + config.textStroke + "px !important;"); + } + lines.push('}'); + return lines.join('\n'); + } + + var FilterMode; + (function (FilterMode) { + FilterMode[FilterMode["light"] = 0] = "light"; + FilterMode[FilterMode["dark"] = 1] = "dark"; + })(FilterMode || (FilterMode = {})); + function getCSSFilterValue(config) { + var filters = []; + if (config.mode === FilterMode.dark) { + filters.push('invert(100%) hue-rotate(180deg)'); + } + if (config.brightness !== 100) { + filters.push("brightness(" + config.brightness + "%)"); + } + if (config.contrast !== 100) { + filters.push("contrast(" + config.contrast + "%)"); + } + if (config.grayscale !== 0) { + filters.push("grayscale(" + config.grayscale + "%)"); + } + if (config.sepia !== 0) { + filters.push("sepia(" + config.sepia + "%)"); + } + if (filters.length === 0) { + return null; + } + return filters.join(' '); + } + + function toSVGMatrix(matrix) { + return matrix.slice(0, 4).map(function (m) { return m.map(function (m) { return m.toFixed(3); }).join(' '); }).join(' '); + } + function getSVGFilterMatrixValue(config) { + return toSVGMatrix(createFilterMatrix(config)); + } + + var counter = 0; + var resolvers = new Map(); + var rejectors = new Map(); + function bgFetch(request) { + return new Promise(function (resolve, reject) { + var id = ++counter; + resolvers.set(id, resolve); + rejectors.set(id, reject); + chrome.runtime.sendMessage({ type: 'fetch', data: request, id: id }); + }); + } + chrome.runtime.onMessage.addListener(function (_a) { + var type = _a.type, data = _a.data, error = _a.error, id = _a.id; + if (type === 'fetch-response') { + var resolve = resolvers.get(id); + var reject = rejectors.get(id); + resolvers.delete(id); + rejectors.delete(id); + if (error) { + reject && reject(error); + } + else { + resolve && resolve(data); + } + } + }); + + function getImageDetails(url) { + return __awaiter(this, void 0, void 0, function () { + var dataURL, image, info; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!url.startsWith('data:')) return [3, 1]; + dataURL = url; + return [3, 3]; + case 1: return [4, getImageDataURL(url)]; + case 2: + dataURL = _a.sent(); + _a.label = 3; + case 3: return [4, urlToImage(dataURL)]; + case 4: + image = _a.sent(); + info = analyzeImage(image); + return [2, __assign({ src: url, dataURL: dataURL, width: image.naturalWidth, height: image.naturalHeight }, info)]; + } + }); + }); + } + function getImageDataURL(url) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!(getURLHost(url) === location.host)) return [3, 2]; + return [4, loadAsDataURL(url)]; + case 1: return [2, _a.sent()]; + case 2: return [4, bgFetch({ url: url, responseType: 'data-url' })]; + case 3: return [2, _a.sent()]; + } + }); + }); + } + function urlToImage(url) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2, new Promise(function (resolve, reject) { + var image = new Image(); + image.onload = function () { return resolve(image); }; + image.onerror = function () { return reject("Unable to load image " + url); }; + image.src = url; + })]; + }); + }); + } + function analyzeImage(image) { + var MAX_ANALIZE_PIXELS_COUNT = 32 * 32; + var naturalPixelsCount = image.naturalWidth * image.naturalHeight; + var k = Math.min(1, Math.sqrt(MAX_ANALIZE_PIXELS_COUNT / naturalPixelsCount)); + var width = Math.max(1, Math.round(image.naturalWidth * k)); + var height = Math.max(1, Math.round(image.naturalHeight * k)); + var canvas = document.createElement('canvas'); + canvas.width = width; + canvas.height = height; + var context = canvas.getContext('2d'); + context.imageSmoothingEnabled = false; + context.drawImage(image, 0, 0, width, height); + var imageData = context.getImageData(0, 0, width, height); + var d = imageData.data; + var TRANSPARENT_ALPHA_THRESHOLD = 0.05; + var DARK_LIGHTNESS_THRESHOLD = 0.4; + var LIGHT_LIGHTNESS_THRESHOLD = 0.7; + var transparentPixelsCount = 0; + var darkPixelsCount = 0; + var lightPixelsCount = 0; + var i, x, y; + var r, g, b, a; + var l, min, max; + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + i = 4 * (y * width + x); + r = d[i + 0] / 255; + g = d[i + 1] / 255; + b = d[i + 2] / 255; + a = d[i + 3] / 255; + if (a < TRANSPARENT_ALPHA_THRESHOLD) { + transparentPixelsCount++; + } + else { + min = Math.min(r, g, b); + max = Math.max(r, g, b); + l = (max + min) / 2; + if (l < DARK_LIGHTNESS_THRESHOLD) { + darkPixelsCount++; + } + if (l > LIGHT_LIGHTNESS_THRESHOLD) { + lightPixelsCount++; + } + } + } + } + var totalPixelsCount = width * height; + var opaquePixelsCount = totalPixelsCount - transparentPixelsCount; + var DARK_IMAGE_THRESHOLD = 0.7; + var LIGHT_IMAGE_THRESHOLD = 0.7; + var TRANSPARENT_IMAGE_THRESHOLD = 0.1; + var LARGE_IMAGE_PIXELS_COUNT = 800 * 600; + return { + isDark: ((darkPixelsCount / opaquePixelsCount) >= DARK_IMAGE_THRESHOLD), + isLight: ((lightPixelsCount / opaquePixelsCount) >= LIGHT_IMAGE_THRESHOLD), + isTransparent: ((transparentPixelsCount / totalPixelsCount) >= TRANSPARENT_IMAGE_THRESHOLD), + isLarge: (naturalPixelsCount >= LARGE_IMAGE_PIXELS_COUNT), + }; + } + function getFilteredImageDataURL(_a, filter) { + var dataURL = _a.dataURL, width = _a.width, height = _a.height; + var matrix = getSVGFilterMatrixValue(filter); + var svg = [ + "", + '', + '', + "", + '', + '', + "", + '', + ].join(''); + var bytes = new Uint8Array(svg.length); + for (var i = 0; i < svg.length; i++) { + bytes[i] = svg.charCodeAt(i); + } + var blob = new Blob([bytes], { type: 'image/svg+xml' }); + var objectURL = URL.createObjectURL(blob); + return objectURL; + } + + function getModifiableCSSDeclaration(property, value, rule, isCancelled) { + var important = Boolean(rule && rule.style && rule.style.getPropertyPriority(property)); + var sourceValue = value; + if (property.startsWith('--')) { + return null; + } + else if ((property.indexOf('color') >= 0 && property !== '-webkit-print-color-adjust') || + property === 'fill' || + property === 'stroke') { + var modifier = getColorModifier(property, value); + if (modifier) { + return { property: property, value: modifier, important: important, sourceValue: sourceValue }; + } + } + else if (property === 'background-image') { + var modifier = getBgImageModifier(property, value, rule, isCancelled); + if (modifier) { + return { property: property, value: modifier, important: important, sourceValue: sourceValue }; + } + } + else if (property.indexOf('shadow') >= 0) { + var modifier = getShadowModifier(property, value); + if (modifier) { + return { property: property, value: modifier, important: important, sourceValue: sourceValue }; + } + } + return null; + } + function getModifiedUserAgentStyle(filter, isIFrame) { + var lines = []; + if (!isIFrame) { + lines.push('html {'); + lines.push(" background-color: " + modifyBackgroundColor({ r: 255, g: 255, b: 255 }, filter) + " !important;"); + lines.push('}'); + } + lines.push((isIFrame ? '' : 'html, body, ') + "input, textarea, select, button {"); + lines.push(" background-color: " + modifyBackgroundColor({ r: 255, g: 255, b: 255 }, filter) + ";"); + lines.push('}'); + lines.push('html, body, input, textarea, select, button {'); + lines.push(" border-color: " + modifyBorderColor({ r: 76, g: 76, b: 76 }, filter) + ";"); + lines.push(" color: " + modifyForegroundColor({ r: 0, g: 0, b: 0 }, filter) + ";"); + lines.push('}'); + lines.push('a {'); + lines.push(" color: " + modifyForegroundColor({ r: 0, g: 64, b: 255 }, filter) + ";"); + lines.push('}'); + lines.push('table {'); + lines.push(" border-color: " + modifyBorderColor({ r: 128, g: 128, b: 128 }, filter) + ";"); + lines.push('}'); + lines.push('::placeholder {'); + lines.push(" color: " + modifyForegroundColor({ r: 169, g: 169, b: 169 }, filter) + ";"); + lines.push('}'); + ['::selection', '::-moz-selection'].forEach(function (selection) { + lines.push(selection + " {"); + lines.push(" background-color: " + modifyBackgroundColor({ r: 0, g: 96, b: 212 }, filter) + ";"); + lines.push(" color: " + modifyForegroundColor({ r: 255, g: 255, b: 255 }, filter) + ";"); + lines.push('}'); + }); + lines.push('input:-webkit-autofill,'); + lines.push('textarea:-webkit-autofill,'); + lines.push('select:-webkit-autofill {'); + lines.push(" background-color: " + modifyBackgroundColor({ r: 250, g: 255, b: 189 }, filter) + " !important;"); + lines.push(" color: " + modifyForegroundColor({ r: 0, g: 0, b: 0 }, filter) + " !important;"); + lines.push('}'); + if (!isMacOS()) { + lines.push('::-webkit-scrollbar {'); + lines.push(" background-color: " + modifyBackgroundColor({ r: 241, g: 241, b: 241 }, filter) + ";"); + lines.push(" color: " + modifyForegroundColor({ r: 96, g: 96, b: 96 }, filter) + ";"); + lines.push('}'); + lines.push('::-webkit-scrollbar-thumb {'); + lines.push(" background-color: " + modifyBackgroundColor({ r: 193, g: 193, b: 193 }, filter) + ";"); + lines.push('}'); + lines.push('::-webkit-scrollbar-thumb:hover {'); + lines.push(" background-color: " + modifyBackgroundColor({ r: 166, g: 166, b: 166 }, filter) + ";"); + lines.push('}'); + lines.push('::-webkit-scrollbar-thumb:active {'); + lines.push(" background-color: " + modifyBackgroundColor({ r: 96, g: 96, b: 96 }, filter) + ";"); + lines.push('}'); + lines.push('::-webkit-scrollbar-corner {'); + lines.push(" background-color: " + modifyBackgroundColor({ r: 255, g: 255, b: 255 }, filter) + ";"); + lines.push('}'); + lines.push('* {'); + lines.push(" scrollbar-color: " + modifyBackgroundColor({ r: 193, g: 193, b: 193 }, filter) + " " + modifyBackgroundColor({ r: 241, g: 241, b: 241 }, filter) + ";"); + lines.push('}'); + } + return lines.join('\n'); + } + function getModifiedFallbackStyle(filter, _a) { + var strict = _a.strict; + var lines = []; + lines.push("html, body, " + (strict ? 'body *' : 'body > *') + " {"); + lines.push(" background-color: " + modifyBackgroundColor({ r: 255, g: 255, b: 255 }, filter) + " !important;"); + lines.push(" border-color: " + modifyBorderColor({ r: 64, g: 64, b: 64 }, filter) + " !important;"); + lines.push(" color: " + modifyForegroundColor({ r: 0, g: 0, b: 0 }, filter) + " !important;"); + lines.push('}'); + return lines.join('\n'); + } + var unparsableColors = new Set([ + 'inherit', + 'transparent', + 'initial', + 'currentcolor', + 'none', + ]); + var colorParseCache = new Map(); + function parseColorWithCache($color) { + $color = $color.trim(); + if (colorParseCache.has($color)) { + return colorParseCache.get($color); + } + var color = parse($color); + colorParseCache.set($color, color); + return color; + } + function tryParseColor($color) { + try { + return parseColorWithCache($color); + } + catch (err) { + return null; + } + } + function getColorModifier(prop, value) { + if (unparsableColors.has(value.toLowerCase())) { + return value; + } + try { + var rgb_1 = parseColorWithCache(value); + if (prop.indexOf('background') >= 0) { + return function (filter) { return modifyBackgroundColor(rgb_1, filter); }; + } + if (prop.indexOf('border') >= 0 || prop.indexOf('outline') >= 0) { + return function (filter) { return modifyBorderColor(rgb_1, filter); }; + } + return function (filter) { return modifyForegroundColor(rgb_1, filter); }; + } + catch (err) { + logWarn('Color parse error', err); + return null; + } + } + var gradientRegex = /[\-a-z]+gradient\(([^\(\)]*(\(([^\(\)]*(\(.*?\)))*[^\(\)]*\))){0,15}[^\(\)]*\)/g; + var imageDetailsCache = new Map(); + var awaitingForImageLoading = new Map(); + function getBgImageModifier(prop, value, rule, isCancelled) { + var _this = this; + try { + var gradients = getMatches(gradientRegex, value); + var urls = getMatches(cssURLRegex, value); + if (urls.length === 0 && gradients.length === 0) { + return value; + } + var getIndices = function (matches) { + var index = 0; + return matches.map(function (match) { + var valueIndex = value.indexOf(match, index); + index = valueIndex + match.length; + return { match: match, index: valueIndex }; + }); + }; + var matches_1 = getIndices(urls).map(function (i) { return (__assign({ type: 'url' }, i)); }) + .concat(getIndices(gradients).map(function (i) { return (__assign({ type: 'gradient' }, i)); })) + .sort(function (a, b) { return a.index - b.index; }); + var getGradientModifier_1 = function (gradient) { + var match = gradient.match(/^(.*-gradient)\((.*)\)$/); + var type = match[1]; + var content = match[2]; + var partsRegex = /([^\(\),]+(\([^\(\)]*(\([^\(\)]*\)*[^\(\)]*)?\))?[^\(\),]*),?/g; + var colorStopRegex = /^(from|color-stop|to)\(([^\(\)]*?,\s*)?(.*?)\)$/; + var parts = getMatches(partsRegex, content, 1).map(function (part) { + part = part.trim(); + var rgb = tryParseColor(part); + if (rgb) { + return function (filter) { return modifyGradientColor(rgb, filter); }; + } + var space = part.lastIndexOf(' '); + rgb = tryParseColor(part.substring(0, space)); + if (rgb) { + return function (filter) { return modifyGradientColor(rgb, filter) + " " + part.substring(space + 1); }; + } + var colorStopMatch = part.match(colorStopRegex); + if (colorStopMatch) { + rgb = tryParseColor(colorStopMatch[3]); + if (rgb) { + return function (filter) { return colorStopMatch[1] + "(" + (colorStopMatch[2] ? colorStopMatch[2] + ", " : '') + modifyGradientColor(rgb, filter) + ")"; }; + } + } + return function () { return part; }; + }); + return function (filter) { + return type + "(" + parts.map(function (modify) { return modify(filter); }).join(', ') + ")"; + }; + }; + var getURLModifier_1 = function (urlValue) { + var url = getCSSURLValue(urlValue); + if (rule.parentStyleSheet.href) { + var basePath = getCSSBaseBath(rule.parentStyleSheet.href); + url = getAbsoluteURL(basePath, url); + } + else if (rule.parentStyleSheet.ownerNode && rule.parentStyleSheet.ownerNode.baseURI) { + url = getAbsoluteURL(rule.parentStyleSheet.ownerNode.baseURI, url); + } + else { + url = getAbsoluteURL(location.origin, url); + } + var absoluteValue = "url(\"" + url + "\")"; + return function (filter) { return __awaiter(_this, void 0, void 0, function () { + var imageDetails, awaiters_1, err_1, bgImageValue; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!imageDetailsCache.has(url)) return [3, 1]; + imageDetails = imageDetailsCache.get(url); + return [3, 7]; + case 1: + _a.trys.push([1, 6, , 7]); + if (!awaitingForImageLoading.has(url)) return [3, 3]; + awaiters_1 = awaitingForImageLoading.get(url); + return [4, new Promise(function (resolve) { return awaiters_1.push(resolve); })]; + case 2: + imageDetails = _a.sent(); + if (!imageDetails) { + return [2, null]; + } + return [3, 5]; + case 3: + awaitingForImageLoading.set(url, []); + return [4, getImageDetails(url)]; + case 4: + imageDetails = _a.sent(); + imageDetailsCache.set(url, imageDetails); + awaitingForImageLoading.get(url).forEach(function (resolve) { return resolve(imageDetails); }); + awaitingForImageLoading.delete(url); + _a.label = 5; + case 5: + if (isCancelled()) { + return [2, null]; + } + return [3, 7]; + case 6: + err_1 = _a.sent(); + logWarn(err_1); + if (awaitingForImageLoading.has(url)) { + awaitingForImageLoading.get(url).forEach(function (resolve) { return resolve(null); }); + awaitingForImageLoading.delete(url); + } + return [2, absoluteValue]; + case 7: + bgImageValue = getBgImageValue_1(imageDetails, filter) || absoluteValue; + return [2, bgImageValue]; + } + }); + }); }; + }; + var getBgImageValue_1 = function (imageDetails, filter) { + var isDark = imageDetails.isDark, isLight = imageDetails.isLight, isTransparent = imageDetails.isTransparent, isLarge = imageDetails.isLarge, width = imageDetails.width; + var result; + if (isDark && isTransparent && filter.mode === 1 && !isLarge && width > 2) { + logInfo("Inverting dark image " + imageDetails.src); + var inverted = getFilteredImageDataURL(imageDetails, __assign(__assign({}, filter), { sepia: clamp(filter.sepia + 10, 0, 100) })); + result = "url(\"" + inverted + "\")"; + } + else if (isLight && !isTransparent && filter.mode === 1) { + if (isLarge) { + result = 'none'; + } + else { + logInfo("Dimming light image " + imageDetails.src); + var dimmed = getFilteredImageDataURL(imageDetails, filter); + result = "url(\"" + dimmed + "\")"; + } + } + else if (filter.mode === 0 && isLight && !isLarge) { + logInfo("Applying filter to image " + imageDetails.src); + var filtered = getFilteredImageDataURL(imageDetails, __assign(__assign({}, filter), { brightness: clamp(filter.brightness - 10, 5, 200), sepia: clamp(filter.sepia + 10, 0, 100) })); + result = "url(\"" + filtered + "\")"; + } + else { + result = null; + } + return result; + }; + var modifiers_1 = []; + var index_1 = 0; + matches_1.forEach(function (_a, i) { + var match = _a.match, type = _a.type, matchStart = _a.index; + var prefixStart = index_1; + var matchEnd = matchStart + match.length; + index_1 = matchEnd; + modifiers_1.push(function () { return value.substring(prefixStart, matchStart); }); + modifiers_1.push(type === 'url' ? getURLModifier_1(match) : getGradientModifier_1(match)); + if (i === matches_1.length - 1) { + modifiers_1.push(function () { return value.substring(matchEnd); }); + } + }); + return function (filter) { + var results = modifiers_1.map(function (modify) { return modify(filter); }); + if (results.some(function (r) { return r instanceof Promise; })) { + return Promise.all(results) + .then(function (asyncResults) { + return asyncResults.join(''); + }); + } + return results.join(''); + }; + } + catch (err) { + logWarn("Unable to parse gradient " + value, err); + return null; + } + } + function getShadowModifier(prop, value) { + try { + var index_2 = 0; + var colorMatches_1 = getMatches(/(^|\s)([a-z]+\(.+?\)|#[0-9a-f]+|[a-z]+)(.*?(inset|outset)?($|,))/ig, value, 2); + var modifiers_2 = colorMatches_1.map(function (match, i) { + var prefixIndex = index_2; + var matchIndex = value.indexOf(match, index_2); + var matchEnd = matchIndex + match.length; + index_2 = matchEnd; + var rgb = tryParseColor(match); + if (!rgb) { + return function () { return value.substring(prefixIndex, matchEnd); }; + } + return function (filter) { return "" + value.substring(prefixIndex, matchIndex) + modifyShadowColor(rgb, filter) + (i === colorMatches_1.length - 1 ? value.substring(matchEnd) : ''); }; + }); + return function (filter) { return modifiers_2.map(function (modify) { return modify(filter); }).join(''); }; + } + catch (err) { + logWarn("Unable to parse shadow " + value, err); + return null; + } + } + function cleanModificationCache() { + colorParseCache.clear(); + clearColorModificationCache(); + imageDetailsCache.clear(); + awaitingForImageLoading.clear(); + } + + var overrides = { + 'background-color': { + customProp: '--darkreader-inline-bgcolor', + cssProp: 'background-color', + dataAttr: 'data-darkreader-inline-bgcolor', + store: new WeakSet(), + }, + 'background-image': { + customProp: '--darkreader-inline-bgimage', + cssProp: 'background-image', + dataAttr: 'data-darkreader-inline-bgimage', + store: new WeakSet(), + }, + 'border-color': { + customProp: '--darkreader-inline-border', + cssProp: 'border-color', + dataAttr: 'data-darkreader-inline-border', + store: new WeakSet(), + }, + 'border-bottom-color': { + customProp: '--darkreader-inline-border-bottom', + cssProp: 'border-bottom-color', + dataAttr: 'data-darkreader-inline-border-bottom', + store: new WeakSet(), + }, + 'border-left-color': { + customProp: '--darkreader-inline-border-left', + cssProp: 'border-left-color', + dataAttr: 'data-darkreader-inline-border-left', + store: new WeakSet(), + }, + 'border-right-color': { + customProp: '--darkreader-inline-border-right', + cssProp: 'border-right-color', + dataAttr: 'data-darkreader-inline-border-right', + store: new WeakSet(), + }, + 'border-top-color': { + customProp: '--darkreader-inline-border-top', + cssProp: 'border-top-color', + dataAttr: 'data-darkreader-inline-border-top', + store: new WeakSet(), + }, + 'box-shadow': { + customProp: '--darkreader-inline-boxshadow', + cssProp: 'box-shadow', + dataAttr: 'data-darkreader-inline-boxshadow', + store: new WeakSet(), + }, + 'color': { + customProp: '--darkreader-inline-color', + cssProp: 'color', + dataAttr: 'data-darkreader-inline-color', + store: new WeakSet(), + }, + 'fill': { + customProp: '--darkreader-inline-fill', + cssProp: 'fill', + dataAttr: 'data-darkreader-inline-fill', + store: new WeakSet(), + }, + 'stroke': { + customProp: '--darkreader-inline-stroke', + cssProp: 'stroke', + dataAttr: 'data-darkreader-inline-stroke', + store: new WeakSet(), + }, + 'outline-color': { + customProp: '--darkreader-inline-outline', + cssProp: 'outline-color', + dataAttr: 'data-darkreader-inline-outline', + store: new WeakSet(), + }, + }; + var overridesList = Object.values(overrides); + var INLINE_STYLE_ATTRS = ['style', 'fill', 'stroke', 'bgcolor', 'color']; + var INLINE_STYLE_SELECTOR = INLINE_STYLE_ATTRS.map(function (attr) { return "[" + attr + "]"; }).join(', '); + function getInlineOverrideStyle() { + return overridesList.map(function (_a) { + var dataAttr = _a.dataAttr, customProp = _a.customProp, cssProp = _a.cssProp; + return [ + "[" + dataAttr + "] {", + " " + cssProp + ": var(" + customProp + ") !important;", + '}', + ].join('\n'); + }).join('\n'); + } + function expand(nodes, selector) { + var results = []; + nodes.forEach(function (n) { + if (n instanceof Element) { + if (n.matches(selector)) { + results.push(n); + } + results.push.apply(results, Array.from(n.querySelectorAll(selector))); + } + }); + return results; + } + var observers = new Map(); + function watchForInlineStyles(elementStyleDidChange, shadowRootDiscovered) { + deepWatchForInlineStyles(document.documentElement, elementStyleDidChange, shadowRootDiscovered); + iterateShadowNodes(document.documentElement, function (node) { + deepWatchForInlineStyles(node.shadowRoot, elementStyleDidChange, shadowRootDiscovered); + }); + } + function deepWatchForInlineStyles(root, elementStyleDidChange, shadowRootDiscovered) { + if (observers.has(root)) { + observers.get(root).disconnect(); + } + var observer = new MutationObserver(function (mutations) { + mutations.forEach(function (m) { + var createdInlineStyles = expand(Array.from(m.addedNodes), INLINE_STYLE_SELECTOR); + if (createdInlineStyles.length > 0) { + createdInlineStyles.forEach(function (el) { return elementStyleDidChange(el); }); + } + if (m.type === 'attributes') { + if (INLINE_STYLE_ATTRS.includes(m.attributeName)) { + elementStyleDidChange(m.target); + } + overridesList + .filter(function (_a) { + var store = _a.store, dataAttr = _a.dataAttr; + return store.has(m.target) && !m.target.hasAttribute(dataAttr); + }) + .forEach(function (_a) { + var dataAttr = _a.dataAttr; + return m.target.setAttribute(dataAttr, ''); + }); + } + }); + mutations.forEach(function (m) { + m.addedNodes.forEach(function (added) { + if (added.isConnected) { + iterateShadowNodes(added, function (n) { + shadowRootDiscovered(n.shadowRoot); + deepWatchForInlineStyles(n.shadowRoot, elementStyleDidChange, shadowRootDiscovered); + }); + } + }); + }); + }); + observer.observe(root, { + childList: true, + subtree: true, + attributes: true, + attributeFilter: INLINE_STYLE_ATTRS.concat(overridesList.map(function (_a) { + var dataAttr = _a.dataAttr; + return dataAttr; + })), + }); + observers.set(root, observer); + } + function stopWatchingForInlineStyles() { + observers.forEach(function (o) { return o.disconnect(); }); + observers.clear(); + } + var inlineStyleCache = new WeakMap(); + var filterProps = ['brightness', 'contrast', 'grayscale', 'sepia', 'mode']; + function getInlineStyleCacheKey(el, theme) { + return INLINE_STYLE_ATTRS + .map(function (attr) { return attr + "=\"" + el.getAttribute(attr) + "\""; }) + .concat(filterProps.map(function (prop) { return prop + "=\"" + theme[prop] + "\""; })) + .join(' '); + } + function overrideInlineStyle(element, theme) { + var cacheKey = getInlineStyleCacheKey(element, theme); + if (cacheKey === inlineStyleCache.get(element)) { + return; + } + var unsetProps = new Set(Object.keys(overrides)); + function setCustomProp(targetCSSProp, modifierCSSProp, cssVal) { + var _a = overrides[targetCSSProp], customProp = _a.customProp, dataAttr = _a.dataAttr; + var mod = getModifiableCSSDeclaration(modifierCSSProp, cssVal, null, null); + if (!mod) { + return; + } + var value = mod.value; + if (typeof value === 'function') { + value = value(theme); + } + element.style.setProperty(customProp, value); + if (!element.hasAttribute(dataAttr)) { + element.setAttribute(dataAttr, ''); + } + unsetProps.delete(targetCSSProp); + } + if (element.hasAttribute('bgcolor')) { + var value = element.getAttribute('bgcolor'); + if (value.match(/^[0-9a-f]{3}$/i) || value.match(/^[0-9a-f]{6}$/i)) { + value = "#" + value; + } + setCustomProp('background-color', 'background-color', value); + } + if (element.hasAttribute('color')) { + var value = element.getAttribute('color'); + if (value.match(/^[0-9a-f]{3}$/i) || value.match(/^[0-9a-f]{6}$/i)) { + value = "#" + value; + } + setCustomProp('color', 'color', value); + } + if (element.hasAttribute('fill') && element instanceof SVGElement) { + var SMALL_SVG_LIMIT = 32; + var value = element.getAttribute('fill'); + var isBg = false; + if (!(element instanceof SVGTextElement)) { + var _a = element.getBoundingClientRect(), width = _a.width, height = _a.height; + isBg = (width > SMALL_SVG_LIMIT || height > SMALL_SVG_LIMIT); + } + setCustomProp('fill', isBg ? 'background-color' : 'color', value); + } + if (element.hasAttribute('stroke')) { + var value = element.getAttribute('stroke'); + setCustomProp('stroke', element instanceof SVGLineElement || element instanceof SVGTextElement ? 'border-color' : 'color', value); + } + element.style && iterateCSSDeclarations(element.style, function (property, value) { + if (property === 'background-image' && value.indexOf('url') >= 0) { + return; + } + if (overrides.hasOwnProperty(property)) { + setCustomProp(property, property, value); + } + }); + if (element.style && element instanceof SVGTextElement && element.style.fill) { + setCustomProp('fill', 'color', element.style.getPropertyValue('fill')); + } + Array.from(unsetProps).forEach(function (cssProp) { + var _a = overrides[cssProp], store = _a.store, dataAttr = _a.dataAttr; + store.delete(element); + element.removeAttribute(dataAttr); + }); + inlineStyleCache.set(element, getInlineStyleCacheKey(element, theme)); + } + + var metaThemeColorName = 'theme-color'; + var metaThemeColorSelector = "meta[name=\"" + metaThemeColorName + "\"]"; + var srcMetaThemeColor = null; + var observer = null; + function changeMetaThemeColor(meta, theme) { + srcMetaThemeColor = srcMetaThemeColor || meta.content; + try { + var color = parse(srcMetaThemeColor); + meta.content = modifyBackgroundColor(color, theme); + } + catch (err) { + logWarn(err); + } + } + function changeMetaThemeColorWhenAvailable(theme) { + var meta = document.querySelector(metaThemeColorSelector); + if (meta) { + changeMetaThemeColor(meta, theme); + } + else { + if (observer) { + observer.disconnect(); + } + observer = new MutationObserver(function (mutations) { + loop: for (var _i = 0, mutations_1 = mutations; _i < mutations_1.length; _i++) { + var m = mutations_1[_i]; + for (var _a = 0, _b = Array.from(m.addedNodes); _a < _b.length; _a++) { + var node = _b[_a]; + if (node instanceof HTMLMetaElement && node.name === metaThemeColorName) { + observer.disconnect(); + observer = null; + changeMetaThemeColor(node, theme); + break loop; + } + } + } + }); + observer.observe(document.head, { childList: true }); + } + } + function restoreMetaThemeColor() { + if (observer) { + observer.disconnect(); + observer = null; + } + var meta = document.querySelector(metaThemeColorSelector); + if (meta && srcMetaThemeColor) { + meta.content = srcMetaThemeColor; + } + } + + var STYLE_SELECTOR = (function () { + var selectors = [ + 'html /deep/ link[rel*="stylesheet" i]:not([disabled])', + 'html /deep/ style', + ':host /deep/ link[rel*="stylesheet" i]:not([disabled])', + ':host /deep/ style', + ':host link[rel*="stylesheet" i]:not([disabled])', + ':host style', + ]; + if (!isDeepSelectorSupported()) { + selectors = selectors.map(function (s) { return s.replace('/deep/ ', ''); }); + } + if (!isHostSelectorSupported()) { + selectors = selectors.filter(function (s) { return s.startsWith(':host'); }); + } + return selectors.join(', '); + })(); + function shouldManageStyle(element) { + return (((element instanceof HTMLStyleElement) || + (element instanceof SVGStyleElement) || + (element instanceof HTMLLinkElement && + element.rel && + element.rel.toLowerCase().includes('stylesheet') && + !element.disabled)) && + !element.classList.contains('darkreader') && + element.media !== 'print'); + } + var asyncQueue = createAsyncTasksQueue(); + function manageStyle(element, _a) { + var update = _a.update, loadingStart = _a.loadingStart, loadingEnd = _a.loadingEnd; + var prevStyles = []; + var next = element; + while ((next = next.nextElementSibling) && next.matches('.darkreader')) { + prevStyles.push(next); + } + var corsCopy = prevStyles.find(function (el) { return el.matches('.darkreader--cors'); }) || null; + var syncStyle = prevStyles.find(function (el) { return el.matches('.darkreader--sync'); }) || null; + var corsCopyPositionWatcher = null; + var syncStylePositionWatcher = null; + var cancelAsyncOperations = false; + function isCancelled() { + return cancelAsyncOperations; + } + var observer = new MutationObserver(function () { + update(); + }); + var observerOptions = { attributes: true, childList: true, characterData: true }; + function containsCSSImport() { + return element instanceof HTMLStyleElement && element.textContent.trim().match(cssImportRegex); + } + function getRulesSync() { + if (corsCopy) { + return corsCopy.sheet.cssRules; + } + if (element.sheet == null) { + return null; + } + if (element instanceof HTMLLinkElement) { + try { + return element.sheet.cssRules; + } + catch (err) { + logWarn(err); + return null; + } + } + if (containsCSSImport()) { + return null; + } + return safeGetSheetRules(); + } + function insertStyle() { + if (corsCopy) { + if (element.nextSibling !== corsCopy) { + element.parentNode.insertBefore(corsCopy, element.nextSibling); + } + if (corsCopy.nextSibling !== syncStyle) { + element.parentNode.insertBefore(syncStyle, corsCopy.nextSibling); + } + } + else if (element.nextSibling !== syncStyle) { + element.parentNode.insertBefore(syncStyle, element.nextSibling); + } + } + function createSyncStyle() { + syncStyle = element instanceof SVGStyleElement ? + document.createElementNS('http://www.w3.org/2000/svg', 'style') : + document.createElement('style'); + syncStyle.classList.add('darkreader'); + syncStyle.classList.add('darkreader--sync'); + syncStyle.media = 'screen'; + } + var isLoadingRules = false; + var wasLoadingError = false; + function getRulesAsync() { + return __awaiter(this, void 0, void 0, function () { + var cssText, cssBasePath, err_1, fullCSSText, err_2; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!(element instanceof HTMLLinkElement)) return [3, 6]; + if (!(element.sheet == null)) return [3, 4]; + _a.label = 1; + case 1: + _a.trys.push([1, 3, , 4]); + return [4, linkLoading(element)]; + case 2: + _a.sent(); + if (cancelAsyncOperations) { + return [2, null]; + } + return [3, 4]; + case 3: + err_1 = _a.sent(); + logWarn(err_1); + wasLoadingError = true; + return [2, null]; + case 4: + try { + if (element.sheet.cssRules != null) { + return [2, element.sheet.cssRules]; + } + } + catch (err) { + logWarn(err); + } + return [4, loadText(element.href)]; + case 5: + cssText = _a.sent(); + cssBasePath = getCSSBaseBath(element.href); + if (cancelAsyncOperations) { + return [2, null]; + } + return [3, 7]; + case 6: + if (containsCSSImport()) { + cssText = element.textContent.trim(); + cssBasePath = getCSSBaseBath(location.href); + } + else { + return [2, null]; + } + _a.label = 7; + case 7: + if (!cssText) return [3, 12]; + _a.label = 8; + case 8: + _a.trys.push([8, 10, , 11]); + return [4, replaceCSSImports(cssText, cssBasePath)]; + case 9: + fullCSSText = _a.sent(); + corsCopy = createCORSCopy(element, fullCSSText); + return [3, 11]; + case 10: + err_2 = _a.sent(); + logWarn(err_2); + return [3, 11]; + case 11: + if (corsCopy) { + corsCopyPositionWatcher = watchForNodePosition(corsCopy, { watchParent: true, watchSibling: true }); + return [2, corsCopy.sheet.cssRules]; + } + _a.label = 12; + case 12: return [2, null]; + } + }); + }); + } + function details() { + var rules = getRulesSync(); + if (!rules) { + if (isLoadingRules || wasLoadingError) { + return null; + } + isLoadingRules = true; + loadingStart(); + getRulesAsync().then(function (results) { + isLoadingRules = false; + loadingEnd(); + if (results) { + update(); + } + }).catch(function (err) { + logWarn(err); + isLoadingRules = false; + loadingEnd(); + }); + return null; + } + var variables = getCSSVariables(rules); + return { variables: variables }; + } + function getFilterKey(filter) { + return ['mode', 'brightness', 'contrast', 'grayscale', 'sepia'].map(function (p) { return p + ":" + filter[p]; }).join(';'); + } + var renderId = 0; + var rulesTextCache = new Map(); + var rulesModCache = new Map(); + var prevFilterKey = null; + var forceRestore = false; + function render(filter, variables) { + var rules = getRulesSync(); + if (!rules) { + return; + } + cancelAsyncOperations = false; + var rulesChanged = (rulesModCache.size === 0); + var notFoundCacheKeys = new Set(rulesModCache.keys()); + var filterKey = getFilterKey(filter); + var filterChanged = (filterKey !== prevFilterKey); + var modRules = []; + iterateCSSRules(rules, function (rule) { + var cssText = rule.cssText; + var textDiffersFromPrev = false; + notFoundCacheKeys.delete(cssText); + if (!rulesTextCache.has(cssText)) { + rulesTextCache.set(cssText, cssText); + textDiffersFromPrev = true; + } + var vars = null; + var varsRule = null; + if (variables.size > 0 || cssText.includes('var(')) { + var cssTextWithVariables = replaceCSSVariables(cssText, variables); + if (rulesTextCache.get(cssText) !== cssTextWithVariables) { + rulesTextCache.set(cssText, cssTextWithVariables); + textDiffersFromPrev = true; + vars = document.createElement('style'); + vars.classList.add('darkreader'); + vars.classList.add('darkreader--vars'); + vars.media = 'screen'; + vars.textContent = cssTextWithVariables; + element.parentNode.insertBefore(vars, element.nextSibling); + varsRule = vars.sheet.cssRules[0]; + } + } + if (textDiffersFromPrev) { + rulesChanged = true; + } + else { + modRules.push(rulesModCache.get(cssText)); + return; + } + var modDecs = []; + var targetRule = varsRule || rule; + targetRule && targetRule.style && iterateCSSDeclarations(targetRule.style, function (property, value) { + var mod = getModifiableCSSDeclaration(property, value, rule, isCancelled); + if (mod) { + modDecs.push(mod); + } + }); + var modRule = null; + if (modDecs.length > 0) { + modRule = { selector: rule.selectorText, declarations: modDecs }; + if (rule.parentRule instanceof CSSMediaRule) { + modRule.media = rule.parentRule.media.mediaText; + } + modRules.push(modRule); + } + rulesModCache.set(cssText, modRule); + removeNode(vars); + }); + notFoundCacheKeys.forEach(function (key) { + rulesTextCache.delete(key); + rulesModCache.delete(key); + }); + prevFilterKey = filterKey; + if (!forceRestore && !rulesChanged && !filterChanged) { + return; + } + renderId++; + forceRestore = false; + function setRule(target, index, declarations) { + var selector = declarations[0].selector; + target.insertRule(selector + " {}", index); + var style = target.cssRules.item(index).style; + declarations.forEach(function (_a) { + var property = _a.property, value = _a.value, important = _a.important, sourceValue = _a.sourceValue; + style.setProperty(property, value == null ? sourceValue : value, important ? 'important' : ''); + }); + } + var readyDeclarations = []; + var asyncDeclarations = new Map(); + var asyncDeclarationCounter = 0; + function buildStyleSheet() { + var groups = []; + readyDeclarations.forEach(function (decl, i) { + var mediaGroup; + var selectorGroup; + var prev = i === 0 ? null : readyDeclarations[i - 1]; + var isSameMedia = prev && prev.media === decl.media; + var isSameMediaAndSelector = prev && isSameMedia && prev.selector === decl.selector; + if (isSameMedia) { + mediaGroup = groups[groups.length - 1]; + } + else { + mediaGroup = []; + groups.push(mediaGroup); + } + if (isSameMediaAndSelector) { + selectorGroup = mediaGroup[mediaGroup.length - 1]; + } + else { + selectorGroup = []; + mediaGroup.push(selectorGroup); + } + selectorGroup.push(decl); + }); + if (!syncStyle) { + createSyncStyle(); + } + syncStylePositionWatcher && syncStylePositionWatcher.stop(); + insertStyle(); + var sheet = syncStyle.sheet; + for (var i = sheet.cssRules.length - 1; i >= 0; i--) { + sheet.deleteRule(i); + } + groups.forEach(function (mediaGroup) { + var media = mediaGroup[0][0].media; + var target; + if (media) { + sheet.insertRule("@media " + media + " {}", sheet.cssRules.length); + target = sheet.cssRules[sheet.cssRules.length - 1]; + } + else { + target = sheet; + } + mediaGroup.forEach(function (selectorGroup) { + var asyncItems = selectorGroup.filter(function (_a) { + var value = _a.value; + return value == null; + }); + if (asyncItems.length > 0) { + asyncItems.forEach(function (_a) { + var asyncKey = _a.asyncKey; + return asyncDeclarations.set(asyncKey, { declarations: selectorGroup, target: target, index: target.cssRules.length }); + }); + } + setRule(target, target.cssRules.length, selectorGroup); + }); + }); + if (syncStylePositionWatcher) { + syncStylePositionWatcher.run(); + } + else { + syncStylePositionWatcher = watchForNodePosition(syncStyle, { onRestore: buildStyleSheet, watchSibling: true, watchParent: true }); + } + } + function rebuildAsyncRule(key) { + var _a = asyncDeclarations.get(key), declarations = _a.declarations, target = _a.target, index = _a.index; + target.deleteRule(index); + setRule(target, index, declarations); + asyncDeclarations.delete(key); + } + modRules.filter(function (r) { return r; }).forEach(function (_a) { + var selector = _a.selector, declarations = _a.declarations, media = _a.media; + declarations.forEach(function (_a) { + var property = _a.property, value = _a.value, important = _a.important, sourceValue = _a.sourceValue; + if (typeof value === 'function') { + var modified = value(filter); + if (modified instanceof Promise) { + var index_1 = readyDeclarations.length; + var asyncKey_1 = asyncDeclarationCounter++; + readyDeclarations.push({ media: media, selector: selector, property: property, value: null, important: important, asyncKey: asyncKey_1, sourceValue: sourceValue }); + var promise = modified; + var currentRenderId_1 = renderId; + promise.then(function (asyncValue) { + if (!asyncValue || cancelAsyncOperations || currentRenderId_1 !== renderId) { + return; + } + readyDeclarations[index_1].value = asyncValue; + asyncQueue.add(function () { + if (cancelAsyncOperations || currentRenderId_1 !== renderId) { + return; + } + rebuildAsyncRule(asyncKey_1); + }); + }); + } + else { + readyDeclarations.push({ media: media, selector: selector, property: property, value: modified, important: important, sourceValue: sourceValue }); + } + } + else { + readyDeclarations.push({ media: media, selector: selector, property: property, value: value, important: important, sourceValue: sourceValue }); + } + }); + }); + buildStyleSheet(); + } + var rulesChangeKey = null; + var rulesCheckFrameId = null; + function safeGetSheetRules() { + try { + if (element.sheet == null) { + return null; + } + return element.sheet.cssRules; + } + catch (err) { + logWarn(err); + return null; + } + } + function updateRulesChangeKey() { + var rules = safeGetSheetRules(); + if (rules) { + rulesChangeKey = rules.length; + } + } + function didRulesKeyChange() { + var rules = safeGetSheetRules(); + return rules && rules.length !== rulesChangeKey; + } + function subscribeToSheetChanges() { + updateRulesChangeKey(); + unsubscribeFromSheetChanges(); + var checkForUpdate = function () { + if (didRulesKeyChange()) { + updateRulesChangeKey(); + update(); + } + rulesCheckFrameId = requestAnimationFrame(checkForUpdate); + }; + checkForUpdate(); + } + function unsubscribeFromSheetChanges() { + cancelAnimationFrame(rulesCheckFrameId); + } + function pause() { + observer.disconnect(); + cancelAsyncOperations = true; + corsCopyPositionWatcher && corsCopyPositionWatcher.stop(); + syncStylePositionWatcher && syncStylePositionWatcher.stop(); + unsubscribeFromSheetChanges(); + } + function destroy() { + pause(); + removeNode(corsCopy); + removeNode(syncStyle); + } + function watch() { + observer.observe(element, observerOptions); + if (element instanceof HTMLStyleElement) { + subscribeToSheetChanges(); + } + } + var maxMoveCount = 10; + var moveCount = 0; + function restore() { + if (!syncStyle) { + return; + } + moveCount++; + if (moveCount > maxMoveCount) { + logWarn('Style sheet was moved multiple times', element); + return; + } + logWarn('Restore style', syncStyle, element); + var shouldRestore = syncStyle.sheet == null || syncStyle.sheet.cssRules.length > 0; + insertStyle(); + if (shouldRestore) { + forceRestore = true; + updateRulesChangeKey(); + update(); + } + } + return { + details: details, + render: render, + pause: pause, + destroy: destroy, + watch: watch, + restore: restore, + }; + } + function linkLoading(link) { + return new Promise(function (resolve, reject) { + var cleanUp = function () { + link.removeEventListener('load', onLoad); + link.removeEventListener('error', onError); + }; + var onLoad = function () { + cleanUp(); + resolve(); + }; + var onError = function () { + cleanUp(); + reject("Link loading failed " + link.href); + }; + link.addEventListener('load', onLoad); + link.addEventListener('error', onError); + }); + } + function getCSSImportURL(importDeclaration) { + return getCSSURLValue(importDeclaration.substring(8).replace(/;$/, '')); + } + function loadText(url) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!url.startsWith('data:')) return [3, 3]; + return [4, fetch(url)]; + case 1: return [4, (_a.sent()).text()]; + case 2: return [2, _a.sent()]; + case 3: return [4, bgFetch({ url: url, responseType: 'text', mimeType: 'text/css' })]; + case 4: return [2, _a.sent()]; + } + }); + }); + } + function replaceCSSImports(cssText, basePath) { + return __awaiter(this, void 0, void 0, function () { + var importMatches, _i, importMatches_1, match, importURL, absoluteURL, importedCSS, err_3; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + cssText = removeCSSComments(cssText); + cssText = replaceCSSFontFace(cssText); + cssText = replaceCSSRelativeURLsWithAbsolute(cssText, basePath); + importMatches = getMatches(cssImportRegex, cssText); + _i = 0, importMatches_1 = importMatches; + _a.label = 1; + case 1: + if (!(_i < importMatches_1.length)) return [3, 8]; + match = importMatches_1[_i]; + importURL = getCSSImportURL(match); + absoluteURL = getAbsoluteURL(basePath, importURL); + importedCSS = void 0; + _a.label = 2; + case 2: + _a.trys.push([2, 5, , 6]); + return [4, loadText(absoluteURL)]; + case 3: + importedCSS = _a.sent(); + return [4, replaceCSSImports(importedCSS, getCSSBaseBath(absoluteURL))]; + case 4: + importedCSS = _a.sent(); + return [3, 6]; + case 5: + err_3 = _a.sent(); + logWarn(err_3); + importedCSS = ''; + return [3, 6]; + case 6: + cssText = cssText.split(match).join(importedCSS); + _a.label = 7; + case 7: + _i++; + return [3, 1]; + case 8: + cssText = cssText.trim(); + return [2, cssText]; + } + }); + }); + } + function createCORSCopy(srcElement, cssText) { + if (!cssText) { + return null; + } + var cors = document.createElement('style'); + cors.classList.add('darkreader'); + cors.classList.add('darkreader--cors'); + cors.media = 'screen'; + cors.textContent = cssText; + srcElement.parentNode.insertBefore(cors, srcElement.nextSibling); + cors.sheet.disabled = true; + return cors; + } + + var observer$1 = null; + function getAllManageableStyles(nodes) { + var results = []; + Array.from(nodes).forEach(function (node) { + if (node instanceof Element) { + if (shouldManageStyle(node)) { + results.push(node); + } + } + if (node instanceof Element || node instanceof ShadowRoot) { + results.push.apply(results, Array.from(node.querySelectorAll(STYLE_SELECTOR)).filter(shouldManageStyle)); + } + }); + return results; + } + var undefinedGroups = new Map(); + var elementsDefinitionCallback; + function collectUndefinedElements(root) { + if (!isDefinedSelectorSupported()) { + return; + } + root.querySelectorAll(':not(:defined)') + .forEach(function (el) { + var tag = el.tagName.toLowerCase(); + if (!undefinedGroups.has(tag)) { + undefinedGroups.set(tag, new Set()); + customElementsWhenDefined(tag).then(function () { + if (elementsDefinitionCallback) { + var elements = undefinedGroups.get(tag); + undefinedGroups.delete(tag); + elementsDefinitionCallback(Array.from(elements)); + } + }); + } + undefinedGroups.get(tag).add(el); + }); + } + function customElementsWhenDefined(tag) { + return new Promise(function (resolve) { + if (window.customElements && typeof window.customElements.whenDefined === 'function') { + customElements.whenDefined(tag).then(resolve); + } + else { + var checkIfDefined_1 = function () { + var elements = undefinedGroups.get(tag); + if (elements && elements.size > 0) { + if (elements.values().next().value.matches(':defined')) { + resolve(); + } + else { + requestAnimationFrame(checkIfDefined_1); + } + } + }; + requestAnimationFrame(checkIfDefined_1); + } + }); + } + function watchWhenCustomElementsDefined(callback) { + elementsDefinitionCallback = callback; + } + function unsubscribeFromDefineCustomElements() { + elementsDefinitionCallback = null; + undefinedGroups.clear(); + } + var shadowObservers = new Set(); + var nodesShadowObservers = new WeakMap(); + function unsubscribeFromShadowRootChanges() { + shadowObservers.forEach(function (o) { return o.disconnect(); }); + shadowObservers.clear(); + nodesShadowObservers = new WeakMap(); + } + function watchForStyleChanges(update) { + if (observer$1) { + observer$1.disconnect(); + shadowObservers.forEach(function (o) { return o.disconnect(); }); + shadowObservers.clear(); + nodesShadowObservers = new WeakMap(); + } + function handleMutations(mutations) { + var createdStyles = new Set(); + var updatedStyles = new Set(); + var removedStyles = new Set(); + var movedStyles = new Set(); + var additions = new Set(); + var deletions = new Set(); + var styleUpdates = new Set(); + mutations.forEach(function (m) { + m.addedNodes.forEach(function (n) { return additions.add(n); }); + m.removedNodes.forEach(function (n) { return deletions.add(n); }); + if (m.type === 'attributes' && shouldManageStyle(m.target)) { + styleUpdates.add(m.target); + } + }); + var styleAdditions = getAllManageableStyles(additions); + var styleDeletions = getAllManageableStyles(deletions); + additions.forEach(function (n) { + iterateShadowNodes(n, function (host) { + var shadowStyles = getAllManageableStyles(host.shadowRoot.children); + if (shadowStyles.length > 0) { + styleAdditions.push.apply(styleAdditions, shadowStyles); + } + }); + }); + deletions.forEach(function (n) { + iterateShadowNodes(n, function (host) { + var shadowStyles = getAllManageableStyles(host.shadowRoot.children); + if (shadowStyles.length > 0) { + styleDeletions.push.apply(styleDeletions, shadowStyles); + } + }); + }); + styleDeletions.forEach(function (style) { + if (style.isConnected) { + movedStyles.add(style); + } + else { + removedStyles.add(style); + } + }); + styleUpdates.forEach(function (style) { + if (!removedStyles.has(style)) { + updatedStyles.add(style); + } + }); + styleAdditions.forEach(function (style) { + if (!(removedStyles.has(style) || movedStyles.has(style) || updatedStyles.has(style))) { + createdStyles.add(style); + } + }); + if (createdStyles.size + removedStyles.size + updatedStyles.size > 0) { + update({ + created: Array.from(createdStyles), + updated: Array.from(updatedStyles), + removed: Array.from(removedStyles), + moved: Array.from(movedStyles), + }); + } + additions.forEach(function (n) { + if (n.isConnected) { + iterateShadowNodes(n, subscribeForShadowRootChanges); + if (n instanceof Element) { + collectUndefinedElements(n); + } + } + }); + } + function subscribeForShadowRootChanges(node) { + if (nodesShadowObservers.has(node)) { + return; + } + var shadowObserver = new MutationObserver(handleMutations); + shadowObserver.observe(node.shadowRoot, mutationObserverOptions); + shadowObservers.add(shadowObserver); + nodesShadowObservers.set(node, shadowObserver); + } + var mutationObserverOptions = { childList: true, subtree: true, attributes: true, attributeFilter: ['rel', 'disabled'] }; + observer$1 = new MutationObserver(handleMutations); + observer$1.observe(document.documentElement, mutationObserverOptions); + iterateShadowNodes(document.documentElement, subscribeForShadowRootChanges); + watchWhenCustomElementsDefined(function (hosts) { + var newStyles = getAllManageableStyles(hosts.map(function (h) { return h.shadowRoot; })); + update({ created: newStyles, updated: [], removed: [], moved: [] }); + hosts.forEach(function (h) { return subscribeForShadowRootChanges(h); }); + }); + collectUndefinedElements(document); + } + function stopWatchingForStyleChanges() { + if (observer$1) { + observer$1.disconnect(); + observer$1 = null; + unsubscribeFromShadowRootChanges(); + unsubscribeFromDefineCustomElements(); + } + } + + var styleManagers = new Map(); + var variables = new Map(); + var filter = null; + var fixes = null; + var isIFrame = null; + function createOrUpdateStyle(className, root) { + if (root === void 0) { root = document.head || document; } + var style = root.querySelector("." + className); + if (!style) { + style = document.createElement('style'); + style.classList.add('darkreader'); + style.classList.add(className); + style.media = 'screen'; + } + return style; + } + var stylePositionWatchers = new Map(); + function setupStylePositionWatcher(node, alias) { + stylePositionWatchers.has(alias) && stylePositionWatchers.get(alias).stop(); + stylePositionWatchers.set(alias, watchForNodePosition(node, { watchParent: true, watchSibling: false })); + } + function stopStylePositionWatchers() { + Array.from(stylePositionWatchers.values()).forEach(function (watcher) { return watcher.stop(); }); + stylePositionWatchers.clear(); + } + function createStaticStyleOverrides() { + var fallbackStyle = createOrUpdateStyle('darkreader--fallback'); + document.head.insertBefore(fallbackStyle, document.head.firstChild); + fallbackStyle.textContent = getModifiedFallbackStyle(filter, { strict: true }); + setupStylePositionWatcher(fallbackStyle, 'fallback'); + var userAgentStyle = createOrUpdateStyle('darkreader--user-agent'); + document.head.insertBefore(userAgentStyle, fallbackStyle.nextSibling); + userAgentStyle.textContent = getModifiedUserAgentStyle(filter, isIFrame); + setupStylePositionWatcher(userAgentStyle, 'user-agent'); + var textStyle = createOrUpdateStyle('darkreader--text'); + document.head.insertBefore(textStyle, fallbackStyle.nextSibling); + if (filter.useFont || filter.textStroke > 0) { + textStyle.textContent = createTextStyle(filter); + } + else { + textStyle.textContent = ''; + } + setupStylePositionWatcher(textStyle, 'text'); + var invertStyle = createOrUpdateStyle('darkreader--invert'); + document.head.insertBefore(invertStyle, textStyle.nextSibling); + if (fixes && Array.isArray(fixes.invert) && fixes.invert.length > 0) { + invertStyle.textContent = [ + fixes.invert.join(', ') + " {", + " filter: " + getCSSFilterValue(__assign(__assign({}, filter), { contrast: filter.mode === 0 ? filter.contrast : clamp(filter.contrast - 10, 0, 100) })) + " !important;", + '}', + ].join('\n'); + } + else { + invertStyle.textContent = ''; + } + setupStylePositionWatcher(invertStyle, 'invert'); + var inlineStyle = createOrUpdateStyle('darkreader--inline'); + document.head.insertBefore(inlineStyle, invertStyle.nextSibling); + inlineStyle.textContent = getInlineOverrideStyle(); + setupStylePositionWatcher(inlineStyle, 'inline'); + var overrideStyle = createOrUpdateStyle('darkreader--override'); + document.head.appendChild(overrideStyle); + overrideStyle.textContent = fixes && fixes.css ? replaceCSSTemplates(fixes.css) : ''; + setupStylePositionWatcher(overrideStyle, 'override'); + } + var shadowRootsWithOverrides = new Set(); + function createShadowStaticStyleOverrides(root) { + var inlineStyle = createOrUpdateStyle('darkreader--inline', root); + root.insertBefore(inlineStyle, root.firstChild); + inlineStyle.textContent = getInlineOverrideStyle(); + shadowRootsWithOverrides.add(root); + } + function replaceCSSTemplates($cssText) { + return $cssText.replace(/\${(.+?)}/g, function (m0, $color) { + try { + var color = parseColorWithCache($color); + return modifyColor(color, filter); + } + catch (err) { + logWarn(err); + return $color; + } + }); + } + function cleanFallbackStyle() { + var fallback = document.head.querySelector('.darkreader--fallback'); + if (fallback) { + fallback.textContent = ''; + } + } + function createDynamicStyleOverrides() { + cancelRendering(); + updateVariables(getElementCSSVariables(document.documentElement)); + var allStyles = Array.from(document.querySelectorAll(STYLE_SELECTOR)); + iterateShadowNodes(document.documentElement, function (node) { + var shadowStyles = node.shadowRoot.querySelectorAll(STYLE_SELECTOR); + if (shadowStyles.length > 0) { + allStyles.push.apply(allStyles, Array.from(shadowStyles)); + } + }); + var newManagers = Array.from(allStyles) + .filter(function (style) { return !styleManagers.has(style) && shouldManageStyle(style); }) + .map(function (style) { return createManager(style); }); + var newVariables = newManagers + .map(function (manager) { return manager.details(); }) + .filter(function (details) { return details && details.variables.size > 0; }) + .map(function (_a) { + var variables = _a.variables; + return variables; + }); + if (newVariables.length === 0) { + styleManagers.forEach(function (manager) { return manager.render(filter, variables); }); + if (loadingStyles.size === 0) { + cleanFallbackStyle(); + } + } + else { + newVariables.forEach(function (variables) { return updateVariables(variables); }); + throttledRenderAllStyles(function () { + if (loadingStyles.size === 0) { + cleanFallbackStyle(); + } + }); + } + newManagers.forEach(function (manager) { return manager.watch(); }); + var inlineStyleElements = Array.from(document.querySelectorAll(INLINE_STYLE_SELECTOR)); + iterateShadowNodes(document.documentElement, function (node) { + var elements = node.shadowRoot.querySelectorAll(INLINE_STYLE_SELECTOR); + if (elements.length > 0) { + createShadowStaticStyleOverrides(node.shadowRoot); + inlineStyleElements.push.apply(inlineStyleElements, Array.from(elements)); + } + }); + inlineStyleElements.forEach(function (el) { return overrideInlineStyle(el, filter); }); + } + var loadingStylesCounter = 0; + var loadingStyles = new Set(); + function createManager(element) { + if (styleManagers.has(element)) { + return; + } + var loadingStyleId = ++loadingStylesCounter; + function loadingStart() { + if (!isPageLoaded() || !didDocumentShowUp) { + loadingStyles.add(loadingStyleId); + var fallbackStyle = document.querySelector('.darkreader--fallback'); + if (!fallbackStyle.textContent) { + fallbackStyle.textContent = getModifiedFallbackStyle(filter, { strict: false }); + } + } + } + function loadingEnd() { + loadingStyles.delete(loadingStyleId); + if (loadingStyles.size === 0 && isPageLoaded()) { + cleanFallbackStyle(); + } + } + function update() { + var details = manager.details(); + if (!details) { + return; + } + if (details.variables.size === 0) { + manager.render(filter, variables); + } + else { + updateVariables(details.variables); + throttledRenderAllStyles(); + } + } + var manager = manageStyle(element, { update: update, loadingStart: loadingStart, loadingEnd: loadingEnd }); + styleManagers.set(element, manager); + return manager; + } + function updateVariables(newVars) { + if (newVars.size === 0) { + return; + } + newVars.forEach(function (value, key) { return variables.set(key, value); }); + variables.forEach(function (value, key) { return variables.set(key, replaceCSSVariables(value, variables)); }); + } + function removeManager(element) { + var manager = styleManagers.get(element); + if (manager) { + manager.destroy(); + styleManagers.delete(element); + } + } + var throttledRenderAllStyles = throttle(function (callback) { + styleManagers.forEach(function (manager) { return manager.render(filter, variables); }); + callback && callback(); + }); + var cancelRendering = function () { + throttledRenderAllStyles.cancel(); + }; + function isPageLoaded() { + return document.readyState === 'complete' || document.readyState === 'interactive'; + } + function onReadyStateChange() { + if (!isPageLoaded()) { + return; + } + document.removeEventListener('readystatechange', onReadyStateChange); + if (loadingStyles.size === 0) { + cleanFallbackStyle(); + } + } + var documentVisibilityListener = null; + var didDocumentShowUp = !document.hidden; + function watchForDocumentVisibility(callback) { + var alreadyWatching = Boolean(documentVisibilityListener); + documentVisibilityListener = function () { + if (!document.hidden) { + stopWatchingForDocumentVisibility(); + callback(); + didDocumentShowUp = true; + } + }; + if (!alreadyWatching) { + document.addEventListener('visibilitychange', documentVisibilityListener); + } + } + function stopWatchingForDocumentVisibility() { + document.removeEventListener('visibilitychange', documentVisibilityListener); + documentVisibilityListener = null; + } + function createThemeAndWatchForUpdates() { + createStaticStyleOverrides(); + function runDynamicStyle() { + createDynamicStyleOverrides(); + watchForUpdates(); + } + if (document.hidden) { + watchForDocumentVisibility(runDynamicStyle); + } + else { + runDynamicStyle(); + } + changeMetaThemeColorWhenAvailable(filter); + } + function watchForUpdates() { + watchForStyleChanges(function (_a) { + var created = _a.created, updated = _a.updated, removed = _a.removed, moved = _a.moved; + var stylesToRemove = removed; + var stylesToManage = created.concat(updated).concat(moved) + .filter(function (style) { return !styleManagers.has(style); }); + var stylesToRestore = moved + .filter(function (style) { return styleManagers.has(style); }); + stylesToRemove.forEach(function (style) { return removeManager(style); }); + var newManagers = stylesToManage + .map(function (style) { return createManager(style); }); + var newVariables = newManagers + .map(function (manager) { return manager.details(); }) + .filter(function (details) { return details && details.variables.size > 0; }) + .map(function (_a) { + var variables = _a.variables; + return variables; + }); + if (newVariables.length === 0) { + newManagers.forEach(function (manager) { return manager.render(filter, variables); }); + } + else { + newVariables.forEach(function (variables) { return updateVariables(variables); }); + throttledRenderAllStyles(); + } + newManagers.forEach(function (manager) { return manager.watch(); }); + stylesToRestore.forEach(function (style) { return styleManagers.get(style).restore(); }); + }); + watchForInlineStyles(function (element) { + overrideInlineStyle(element, filter); + if (element === document.documentElement) { + var rootVariables = getElementCSSVariables(document.documentElement); + if (rootVariables.size > 0) { + updateVariables(rootVariables); + throttledRenderAllStyles(); + } + } + }, function (root) { + var inlineStyleElements = root.querySelectorAll(INLINE_STYLE_SELECTOR); + if (inlineStyleElements.length > 0) { + createShadowStaticStyleOverrides(root); + inlineStyleElements.forEach(function (el) { return overrideInlineStyle(el, filter); }); + } + }); + document.addEventListener('readystatechange', onReadyStateChange); + } + function stopWatchingForUpdates() { + styleManagers.forEach(function (manager) { return manager.pause(); }); + stopStylePositionWatchers(); + stopWatchingForStyleChanges(); + stopWatchingForInlineStyles(); + document.removeEventListener('readystatechange', onReadyStateChange); + } + function createOrUpdateDynamicTheme(filterConfig, dynamicThemeFixes, iframe) { + filter = filterConfig; + fixes = dynamicThemeFixes; + isIFrame = iframe; + if (document.head) { + createThemeAndWatchForUpdates(); + } + else { + if (!isFirefox()) { + var fallbackStyle = createOrUpdateStyle('darkreader--fallback'); + document.documentElement.appendChild(fallbackStyle); + fallbackStyle.textContent = getModifiedFallbackStyle(filter, { strict: true }); + } + var headObserver_1 = new MutationObserver(function () { + if (document.head) { + headObserver_1.disconnect(); + createThemeAndWatchForUpdates(); + } + }); + headObserver_1.observe(document, { childList: true, subtree: true }); + } + } + function removeDynamicTheme() { + cleanDynamicThemeCache(); + removeNode(document.querySelector('.darkreader--fallback')); + if (document.head) { + restoreMetaThemeColor(); + removeNode(document.head.querySelector('.darkreader--user-agent')); + removeNode(document.head.querySelector('.darkreader--text')); + removeNode(document.head.querySelector('.darkreader--invert')); + removeNode(document.head.querySelector('.darkreader--inline')); + removeNode(document.head.querySelector('.darkreader--override')); + } + shadowRootsWithOverrides.forEach(function (root) { + removeNode(root.querySelector('.darkreader--inline')); + }); + shadowRootsWithOverrides.clear(); + Array.from(styleManagers.keys()).forEach(function (el) { return removeManager(el); }); + Array.from(document.querySelectorAll('.darkreader')).forEach(removeNode); + } + function cleanDynamicThemeCache() { + stopWatchingForDocumentVisibility(); + cancelRendering(); + stopWatchingForUpdates(); + cleanModificationCache(); + } + + var defaultTheme = { + mode: 1, + brightness: 100, + contrast: 100, + grayscale: 0, + sepia: 0, + useFont: false, + fontFamily: '', + textStroke: 0, + engine: ThemeEngines.dynamicTheme, + stylesheet: '', + }; + var isIFrame$1 = (function () { + try { + return window.self !== window.top; + } + catch (err) { + console.warn(err); + return true; + } + })(); + function enable(themeOptions, fixes) { + if (themeOptions === void 0) { themeOptions = {}; } + if (fixes === void 0) { fixes = null; } + var theme = __assign(__assign({}, defaultTheme), themeOptions); + if (theme.engine !== ThemeEngines.dynamicTheme) { + throw new Error('Theme engine is not supported'); + } + createOrUpdateDynamicTheme(theme, fixes, isIFrame$1); + } + function disable() { + removeDynamicTheme(); + } + var darkScheme = matchMedia('(prefers-color-scheme: dark)'); + var store = { + themeOptions: null, + fixes: null, + }; + function handleColorScheme() { + if (darkScheme.matches) { + enable(store.themeOptions, store.fixes); + } + else { + disable(); + } + } + function auto(themeOptions, fixes) { + if (themeOptions === void 0) { themeOptions = {}; } + if (fixes === void 0) { fixes = null; } + if (themeOptions) { + store = { themeOptions: themeOptions, fixes: fixes }; + handleColorScheme(); + darkScheme.addListener(handleColorScheme); + } + else { + darkScheme.removeListener(handleColorScheme); + disable(); + } + } + var setFetchMethod$1 = setFetchMethod; + + exports.auto = auto; + exports.disable = disable; + exports.enable = enable; + exports.setFetchMethod = setFetchMethod$1; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}))); diff --git a/Wino.Mail.WinUI/JS/libs/jodit.min.css b/Wino.Mail.WinUI/JS/libs/jodit.min.css new file mode 100644 index 00000000..bed4d57f --- /dev/null +++ b/Wino.Mail.WinUI/JS/libs/jodit.min.css @@ -0,0 +1,5664 @@ +.jodit-about { + padding: 20px +} + + .jodit-about a { + color: #459ce7; + text-decoration: none + } + + .jodit-about a:focus, .jodit-about a:hover { + color: #23527c; + outline: 0; + text-decoration: underline + } + + .jodit-about div { + margin-bottom: calc(var(--jd-padding-default)/2) + } + +.jodit-ui-group { + display: inline-flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: wrap; + max-width: 100% +} + +.jodit-ui-group_line_true { + display: flex; + justify-content: stretch +} + +.jodit-ui-group_separated_true:not(:last-child):not(.jodit-ui-group_before-spacer_true):after { + border-left: 0; + border-right: 1px solid var(--jd-color-border); + content: ""; + cursor: default; + margin: 2px; + padding: 0 +} + +.jodit-ui-group:last-child { + border-bottom: 0 +} + +.jodit-ui-list { + display: flex; + flex-direction: column +} + +.jodit-ui-list_mode_vertical .jodit-ui-group { + background-color: transparent; + border: 0; + flex-direction: column +} + +.jodit-ui-list_mode_vertical .jodit-toolbar-button { + height: auto; + min-height: var(--jd-button-size) +} + +.jodit-ui-list_mode_vertical .jodit-toolbar-button__button { + cursor: pointer; + height: auto; + min-height: var(--jd-button-size); + width: 100% +} + +.jodit-ui-list_mode_vertical .jodit-toolbar-button__text:not(:empty) { + justify-content: left +} + +.jodit-ui-separator { + border-left: 0; + border-right: 1px solid var(--jd-color-border); + cursor: default; + margin: 2px; + padding: 0 +} + +.jodit-ui-break { + border-top: 1px solid var(--jd-color-border); + flex-basis: 100%; + height: 0 !important; + width: 0 +} + +.jodit-ui-spacer { + flex: 1 +} + +.jodit-ui-button-icon-text__icon { + display: none +} + + .jodit-ui-button-icon-text__icon:not(:empty) { + display: inline-flex + } + +.jodit-ui-button-icon-text__text { + display: none +} + + .jodit-ui-button-icon-text__text:not(:empty) { + display: inline-flex; + flex-grow: 1; + font-family: var(--jd-font-default); + font-size: var(--jd-font-size-default); + justify-content: center + } + +.jodit-ui-button-icon-text_context_menu .jodit-ui-button-icon-text__text { + justify-content: left; + padding-left: var(--jd-padding-default); + position: relative +} + + .jodit-ui-button-icon-text_context_menu .jodit-ui-button-icon-text__text:before { + border-left: 1px solid var(--jd-color-border); + content: ""; + height: 35px; + left: 0; + position: absolute; + top: calc(var(--jd-padding-default)*-1) + } + +.jodit-ui-button-icon-text__icon:not(:empty) + .jodit-ui-button-icon-text__text:not(:empty) { + margin-left: var(--jd-padding-default) +} + +.jodit-ui-button-icon-text__icon:empty + .jodit-ui-button-icon-text__text:not(:empty) { + padding: 0 var(--jd-padding-default) +} + +.jodit-ui-button-clear, .jodit-ui-button_clear { + appearance: none; + background: 0 0; + border: 0; + box-shadow: none; + box-sizing: border-box; + font-style: normal; + outline: 0; + padding: 0; + position: relative; + text-align: center; + text-decoration: none; + text-transform: none; + user-select: none +} + +.jodit-ui-button-sizes { + height: 34px; + min-width: 34px +} + + .jodit-ui-button-sizes .jodit-icon { + height: 14px; + width: 14px + } + + .jodit-ui-button-sizes button { + appearance: none; + height: 34px; + min-width: 34px; + padding: 0 + } + +.jodit-ui-button-sizes_text-icons_true button { + padding: 0 var(--jd-padding-default) +} + +.jodit-ui-button-sizes_size_tiny { + height: 16px; + min-width: 16px +} + + .jodit-ui-button-sizes_size_tiny .jodit-icon { + height: 8px; + width: 8px + } + + .jodit-ui-button-sizes_size_tiny button { + appearance: none; + height: 16px; + min-width: 16px; + padding: 0 + } + +.jodit-ui-button-sizes_size_tiny_text-icons_true button { + padding: 0 var(--jd-padding-default) +} + +.jodit-ui-button-sizes_size_xsmall { + height: 22px; + min-width: 22px +} + + .jodit-ui-button-sizes_size_xsmall .jodit-icon { + height: 10px; + width: 10px + } + + .jodit-ui-button-sizes_size_xsmall button { + appearance: none; + height: 22px; + min-width: 22px; + padding: 0 + } + +.jodit-ui-button-sizes_size_xsmall_text-icons_true button { + padding: 0 var(--jd-padding-default) +} + +.jodit-ui-button-sizes_size_small { + height: 28px; + min-width: 28px +} + + .jodit-ui-button-sizes_size_small .jodit-icon { + height: 12px; + width: 12px + } + + .jodit-ui-button-sizes_size_small button { + appearance: none; + height: 28px; + min-width: 28px; + padding: 0 + } + +.jodit-ui-button-sizes_size_small_text-icons_true button { + padding: 0 var(--jd-padding-default) +} + +.jodit-ui-button-sizes_size_large { + height: 40px; + min-width: 40px +} + + .jodit-ui-button-sizes_size_large .jodit-icon { + height: 16px; + width: 16px + } + + .jodit-ui-button-sizes_size_large button { + appearance: none; + height: 40px; + min-width: 40px; + padding: 0 + } + +.jodit-ui-button-sizes_size_large_text-icons_true button { + padding: 0 var(--jd-padding-default) +} + +.jodit-ui-button-variants_variant_outline { + border: 1px solid var(--jd-color-border) +} + +.jodit-ui-button-variants_variant_default { + background-color: #e3e3e3; + color: #212529 +} + + .jodit-ui-button-variants_variant_default svg { + fill: #212529; + stroke: #212529 + } + + .jodit-ui-button-variants_variant_default [disabled] { + opacity: .7 + } + + .jodit-ui-button-variants_variant_default:hover:not([disabled]) { + background-color: #c9cdd1; + color: #212529 + } + + .jodit-ui-button-variants_variant_default:hover:not([disabled]) svg { + fill: #212529; + stroke: #212529 + } + + .jodit-ui-button-variants_variant_default:active:not([disabled]) { + background-color: #dae0e5; + color: #212529 + } + + .jodit-ui-button-variants_variant_default:active:not([disabled]) svg { + fill: #212529; + stroke: #212529 + } + + .jodit-ui-button-variants_variant_default:focus:not([disabled]) { + outline: 1px dashed #dae0e5 + } + +.jodit-ui-button-variants_variant_primary { + background-color: #007bff; + color: #fff +} + + .jodit-ui-button-variants_variant_primary svg { + fill: #fff; + stroke: #fff + } + + .jodit-ui-button-variants_variant_primary [disabled] { + opacity: .7 + } + + .jodit-ui-button-variants_variant_primary:hover:not([disabled]) { + background-color: #0069d9; + color: #fff + } + + .jodit-ui-button-variants_variant_primary:hover:not([disabled]) svg { + fill: #fff; + stroke: #fff + } + + .jodit-ui-button-variants_variant_primary:active:not([disabled]) { + background-color: #0062cc; + color: #fff + } + + .jodit-ui-button-variants_variant_primary:active:not([disabled]) svg { + fill: #fff; + stroke: #fff + } + + .jodit-ui-button-variants_variant_primary:focus:not([disabled]) { + outline: 1px dashed #0062cc + } + +.jodit-ui-button-variants_variant_secondary { + background-color: #d8d8d8; + border-radius: 0; + color: #212529 +} + + .jodit-ui-button-variants_variant_secondary svg { + fill: #212529; + stroke: #212529 + } + + .jodit-ui-button-variants_variant_secondary [disabled] { + opacity: .7 + } + + .jodit-ui-button-variants_variant_secondary:hover:not([disabled]) { + background-color: #c9cdd1; + color: #212529 + } + + .jodit-ui-button-variants_variant_secondary:hover:not([disabled]) svg { + fill: #212529; + stroke: #212529 + } + + .jodit-ui-button-variants_variant_secondary:active:not([disabled]) { + background-color: #dae0e5; + color: #212529 + } + + .jodit-ui-button-variants_variant_secondary:active:not([disabled]) svg { + fill: #212529; + stroke: #212529 + } + + .jodit-ui-button-variants_variant_secondary:focus:not([disabled]) { + outline: 1px dashed #dae0e5 + } + +.jodit-ui-button-variants_variant_success { + background-color: #28a745; + color: #fff +} + + .jodit-ui-button-variants_variant_success svg { + fill: #fff; + stroke: #fff + } + + .jodit-ui-button-variants_variant_success [disabled] { + opacity: .7 + } + + .jodit-ui-button-variants_variant_success:hover:not([disabled]) { + background-color: #218838; + color: #fff + } + + .jodit-ui-button-variants_variant_success:hover:not([disabled]) svg { + fill: #fff; + stroke: #fff + } + + .jodit-ui-button-variants_variant_success:active:not([disabled]) { + background-color: #1e7e34; + color: #fff + } + + .jodit-ui-button-variants_variant_success:active:not([disabled]) svg { + fill: #fff; + stroke: #fff + } + + .jodit-ui-button-variants_variant_success:focus:not([disabled]) { + outline: 1px dashed #1e7e34 + } + +.jodit-ui-button-variants_variant_danger { + background-color: #dc3545; + color: #fff +} + + .jodit-ui-button-variants_variant_danger svg { + fill: #fff; + stroke: #fff + } + + .jodit-ui-button-variants_variant_danger [disabled] { + opacity: .7 + } + + .jodit-ui-button-variants_variant_danger:hover:not([disabled]) { + background-color: #c82333; + color: #fff + } + + .jodit-ui-button-variants_variant_danger:hover:not([disabled]) svg { + fill: #fff; + stroke: #fff + } + + .jodit-ui-button-variants_variant_danger:active:not([disabled]) { + background-color: #bd2130; + color: #fff + } + + .jodit-ui-button-variants_variant_danger:active:not([disabled]) svg { + fill: #fff; + stroke: #fff + } + + .jodit-ui-button-variants_variant_danger:focus:not([disabled]) { + outline: 1px dashed #bd2130 + } + +.jodit-ui-button-style { + border-radius: var(--jd-border-radius-default); + padding: 0 var(--jd-padding-default) +} + +.jodit-ui-button, .jodit-ui-button-style { + align-items: center; + color: var(--jd-color-text-icons); + display: inline-flex; + justify-content: center +} + +.jodit-ui-button { + appearance: none; + background: 0 0; + border: 0; + border-radius: var(--jd-border-radius-default); + box-shadow: none; + box-sizing: border-box; + cursor: pointer; + font-style: normal; + height: 34px; + min-width: 34px; + outline: 0; + padding: 0; + padding: 0 var(--jd-padding-default); + position: relative; + text-align: center; + text-decoration: none; + text-transform: none; + user-select: none +} + + .jodit-ui-button:focus-visible:not([disabled]), .jodit-ui-button:hover:not([disabled]) { + background-color: var(--jd-color-button-background-hover); + opacity: 1; + outline: 0 + } + + .jodit-ui-button:active:not([disabled]), .jodit-ui-button[aria-pressed=true]:not([disabled]) { + background-color: var(--jd-color-button-background-hover-opacity40); + outline: 0 + } + + .jodit-ui-button[aria-pressed=true]:hover:not([disabled]) { + background-color: var(--jd-color-button-background-hover-opacity60) + } + + .jodit-ui-button[disabled] { + opacity: .3; + pointer-events: none + } + + .jodit-ui-button .jodit-icon { + height: 14px; + width: 14px + } + + .jodit-ui-button button { + appearance: none; + height: 34px; + min-width: 34px; + padding: 0 + } + +.jodit-ui-button_text-icons_true button { + padding: 0 var(--jd-padding-default) +} + +.jodit-ui-button_size_tiny { + height: 16px; + min-width: 16px +} + + .jodit-ui-button_size_tiny .jodit-icon { + height: 8px; + width: 8px + } + + .jodit-ui-button_size_tiny button { + appearance: none; + height: 16px; + min-width: 16px; + padding: 0 + } + +.jodit-ui-button_size_tiny_text-icons_true button { + padding: 0 var(--jd-padding-default) +} + +.jodit-ui-button_size_xsmall { + height: 22px; + min-width: 22px +} + + .jodit-ui-button_size_xsmall .jodit-icon { + height: 10px; + width: 10px + } + + .jodit-ui-button_size_xsmall button { + appearance: none; + height: 22px; + min-width: 22px; + padding: 0 + } + +.jodit-ui-button_size_xsmall_text-icons_true button { + padding: 0 var(--jd-padding-default) +} + +.jodit-ui-button_size_small { + height: 28px; + min-width: 28px +} + + .jodit-ui-button_size_small .jodit-icon { + height: 12px; + width: 12px + } + + .jodit-ui-button_size_small button { + appearance: none; + height: 28px; + min-width: 28px; + padding: 0 + } + +.jodit-ui-button_size_small_text-icons_true button { + padding: 0 var(--jd-padding-default) +} + +.jodit-ui-button_size_large { + height: 40px; + min-width: 40px +} + + .jodit-ui-button_size_large .jodit-icon { + height: 16px; + width: 16px + } + + .jodit-ui-button_size_large button { + appearance: none; + height: 40px; + min-width: 40px; + padding: 0 + } + +.jodit-ui-button_size_large_text-icons_true button { + padding: 0 var(--jd-padding-default) +} + +.jodit-ui-button__icon { + display: none +} + + .jodit-ui-button__icon:not(:empty) { + display: inline-flex + } + +.jodit-ui-button__text { + display: none +} + + .jodit-ui-button__text:not(:empty) { + display: inline-flex; + flex-grow: 1; + font-family: var(--jd-font-default); + font-size: var(--jd-font-size-default); + justify-content: center + } + +.jodit-ui-button_context_menu .jodit-ui-button__text { + justify-content: left; + padding-left: var(--jd-padding-default); + position: relative +} + + .jodit-ui-button_context_menu .jodit-ui-button__text:before { + border-left: 1px solid var(--jd-color-border); + content: ""; + height: 35px; + left: 0; + position: absolute; + top: calc(var(--jd-padding-default)*-1) + } + +.jodit-ui-button__icon:not(:empty) + .jodit-ui-button__text:not(:empty) { + margin-left: var(--jd-padding-default) +} + +.jodit-ui-button__icon:empty + .jodit-ui-button__text:not(:empty) { + padding: 0 var(--jd-padding-default) +} + +.jodit-ui-button:focus:not([disabled]) { + outline: 1px dashed var(--jd-color-background-selection) +} + +.jodit-ui-button_variant_outline { + border: 1px solid var(--jd-color-border) +} + +.jodit-ui-button_variant_default { + background-color: #e3e3e3; + color: #212529 +} + + .jodit-ui-button_variant_default svg { + fill: #212529; + stroke: #212529 + } + + .jodit-ui-button_variant_default [disabled] { + opacity: .7 + } + + .jodit-ui-button_variant_default:hover:not([disabled]) { + background-color: #c9cdd1; + color: #212529 + } + + .jodit-ui-button_variant_default:hover:not([disabled]) svg { + fill: #212529; + stroke: #212529 + } + + .jodit-ui-button_variant_default:active:not([disabled]) { + background-color: #dae0e5; + color: #212529 + } + + .jodit-ui-button_variant_default:active:not([disabled]) svg { + fill: #212529; + stroke: #212529 + } + + .jodit-ui-button_variant_default:focus:not([disabled]) { + outline: 1px dashed #dae0e5 + } + +.jodit-ui-button_variant_primary { + background-color: #007bff; + color: #fff +} + + .jodit-ui-button_variant_primary svg { + fill: #fff; + stroke: #fff + } + + .jodit-ui-button_variant_primary [disabled] { + opacity: .7 + } + + .jodit-ui-button_variant_primary:hover:not([disabled]) { + background-color: #0069d9; + color: #fff + } + + .jodit-ui-button_variant_primary:hover:not([disabled]) svg { + fill: #fff; + stroke: #fff + } + + .jodit-ui-button_variant_primary:active:not([disabled]) { + background-color: #0062cc; + color: #fff + } + + .jodit-ui-button_variant_primary:active:not([disabled]) svg { + fill: #fff; + stroke: #fff + } + + .jodit-ui-button_variant_primary:focus:not([disabled]) { + outline: 1px dashed #0062cc + } + +.jodit-ui-button_variant_secondary { + background-color: #d8d8d8; + border-radius: 0; + color: #212529 +} + + .jodit-ui-button_variant_secondary svg { + fill: #212529; + stroke: #212529 + } + + .jodit-ui-button_variant_secondary [disabled] { + opacity: .7 + } + + .jodit-ui-button_variant_secondary:hover:not([disabled]) { + background-color: #c9cdd1; + color: #212529 + } + + .jodit-ui-button_variant_secondary:hover:not([disabled]) svg { + fill: #212529; + stroke: #212529 + } + + .jodit-ui-button_variant_secondary:active:not([disabled]) { + background-color: #dae0e5; + color: #212529 + } + + .jodit-ui-button_variant_secondary:active:not([disabled]) svg { + fill: #212529; + stroke: #212529 + } + + .jodit-ui-button_variant_secondary:focus:not([disabled]) { + outline: 1px dashed #dae0e5 + } + +.jodit-ui-button_variant_success { + background-color: #28a745; + color: #fff +} + + .jodit-ui-button_variant_success svg { + fill: #fff; + stroke: #fff + } + + .jodit-ui-button_variant_success [disabled] { + opacity: .7 + } + + .jodit-ui-button_variant_success:hover:not([disabled]) { + background-color: #218838; + color: #fff + } + + .jodit-ui-button_variant_success:hover:not([disabled]) svg { + fill: #fff; + stroke: #fff + } + + .jodit-ui-button_variant_success:active:not([disabled]) { + background-color: #1e7e34; + color: #fff + } + + .jodit-ui-button_variant_success:active:not([disabled]) svg { + fill: #fff; + stroke: #fff + } + + .jodit-ui-button_variant_success:focus:not([disabled]) { + outline: 1px dashed #1e7e34 + } + +.jodit-ui-button_variant_danger { + background-color: #dc3545; + color: #fff +} + + .jodit-ui-button_variant_danger svg { + fill: #fff; + stroke: #fff + } + + .jodit-ui-button_variant_danger [disabled] { + opacity: .7 + } + + .jodit-ui-button_variant_danger:hover:not([disabled]) { + background-color: #c82333; + color: #fff + } + + .jodit-ui-button_variant_danger:hover:not([disabled]) svg { + fill: #fff; + stroke: #fff + } + + .jodit-ui-button_variant_danger:active:not([disabled]) { + background-color: #bd2130; + color: #fff + } + + .jodit-ui-button_variant_danger:active:not([disabled]) svg { + fill: #fff; + stroke: #fff + } + + .jodit-ui-button_variant_danger:focus:not([disabled]) { + outline: 1px dashed #bd2130 + } + +:root { + --jd-popup-box-shadow: 0 4px 1px -2px rgba(76,76,76,.2),0 3px 3px 0 rgba(76,76,76,.15),0 1px 4px 0 rgba(76,76,76,.13) +} + +.jodit-popup { + background: 0 0; + border: 0; + box-shadow: var(--jd-popup-box-shadow); + display: inline-block; + float: none; + height: auto; + margin: 0; + max-width: none; + outline: 0; + padding: 0; + position: static; + position: fixed; + transform: translateZ(0); + width: auto; + z-index: var(--jd-z-index-popup) +} + +.jodit-popup__content { + background: var(--jd-color-background-default); + font-family: var(--jd-font-default); + font-size: var(--jd-font-size-default); + max-height: 300px; + overflow: auto; + padding: var(--jd-padding-default); + overflow-scrolling: touch +} + +.jodit-popup_padding_false .jodit-popup__content { + padding: 0 +} + +.jodit-popup_max-height_false .jodit-popup__content { + max-height: fit-content +} + +.jodit-context-menu { + background: 0 0; + border: 0; + box-shadow: var(--jd-popup-box-shadow); + display: inline-block; + float: none; + height: auto; + margin: 0; + max-width: none; + outline: 0; + padding: 0; + position: static; + position: fixed; + transform: translateZ(0); + width: auto; + z-index: var(--jd-z-index-popup); + z-index: var(--jd-z-index-context-menu) +} + +.jodit-context-menu, .jodit-context-menu__content { + font-family: var(--jd-font-default); + font-size: var(--jd-font-size-default) +} + +.jodit-context-menu__content { + background: var(--jd-color-background-default); + max-height: 300px; + overflow: auto; + padding: var(--jd-padding-default); + overflow-scrolling: touch +} + +.jodit-context-menu_padding_false .jodit-context-menu__content { + padding: 0 +} + +.jodit-context-menu_max-height_false .jodit-context-menu__content { + max-height: fit-content +} + +.jodit-context-menu .jodit-ui-button { + display: flex +} + +.jodit-context-menu button { + width: 100% +} + +.jodit-context-menu_theme_dark { + background-color: var(--jd-dark-background-color) +} + +.jodit-ui-button-group { + margin-bottom: var(--jd-padding-default) +} + +.jodit-ui-button-group__label { + color: var(--jd-color-label); + display: block; + font-size: .8em; + margin-bottom: calc(var(--jd-padding-default)/4) +} + +.jodit-ui-button-group__options { + display: flex; + justify-content: flex-start +} + +.jodit-ui-button-group .jodit-ui-button:not(:last-child) { + border-bottom-right-radius: 0; + border-top-right-radius: 0 +} + +.jodit-ui-button-group .jodit-ui-button + .jodit-ui-button { + border-bottom-left-radius: 0; + border-left: 1px solid var(--jd-color-button-background-hover-opacity40); + border-top-left-radius: 0 +} + +.jodit-ui-button-group .jodit-ui-button[aria-pressed=true]:not([disabled]) { + background-color: var(--jd-color-button-background-hover); + border-left: 0; + box-shadow: inset 0 0 3px 0 var(--jd-color-dark); + color: var(--jd-color-dark); + outline: 0 +} + + .jodit-ui-button-group .jodit-ui-button[aria-pressed=true]:not([disabled]) + .jodit-ui-button { + border: 0 + } + +:root { + --jd-tooltip-color: #fff; + --jd-tooltip-background-color: rgba(0,0,0,.7); + --jd-tooltip-sfx-shadow: rgba(0,0,0,.15); + --jd-tooltip-border-width: 0; + --jd-tooltip-border-color: #e5e5e5 +} + +.jodit-ui-tooltip { + animation-fill-mode: forwards; + animation-timing-function: ease-out; + background-clip: padding-box; + background-color: var(--jd-tooltip-background-color); + border-radius: 4px; + box-shadow: 0 0 0 var(--jd-tooltip-border-width) var(--jd-tooltip-border-color),0 8px 20px var(--jd-tooltip-border-width) var(--jd-tooltip-sfx-shadow); + color: var(--jd-tooltip-color); + font-family: var(--jd-font-default); + font-size: var(--jd-font-size-small); + line-height: 1.4; + max-width: 120px; + opacity: 0; + outline: none; + position: fixed; + text-rendering: optimizelegibility; + transform: translate(-50%,calc(var(--jd-padding-default)/2)); + transition: opacity .2s ease 0s; + user-select: none; + white-space: normal; + width: auto; + z-index: var(--jd-z-index-tooltip) +} + +@media (max-width:768px) { + .jodit-ui-tooltip { + display: none + } +} + +.jodit-ui-tooltip__content { + padding: calc(var(--jd-padding-default)/2) calc(var(--jd-padding-default)*1.5) +} + +.jodit-ui-tooltip.jodit-ui-tooltip_visible_true { + opacity: 1 +} + +.jodit-ui-block { + align-items: center; + display: flex; + justify-content: stretch; + margin-bottom: var(--jd-padding-default) +} + +.jodit-ui-block_width_full { + width: 100% +} + +.jodit-ui-block_align_full { + justify-content: space-between +} + +.jodit-ui-block_align_right { + justify-content: flex-end +} + +.jodit-ui-block_padding_true { + padding: var(--jd-padding-default) +} + +.jodit-ui-label { + color: var(--jd-color-label); + display: block; + font-size: .8em; + margin-bottom: calc(var(--jd-padding-default)/4) +} + +.jodit-ui-input { + display: flex; + flex-direction: column; + margin-bottom: var(--jd-padding-default) +} + +.jodit-ui-input__input { + appearance: none; + background-color: var(--jd-color-white); + border: 0; + border-radius: 0; + box-sizing: border-box; + font-family: var(--jd-font-default); + font-size: var(--jd-font-size-default); + height: var(--jd-input-height); + line-height: 1.2; + outline: none; + padding: 0 var(--jd-padding-default); + width: 100% +} + + .jodit-ui-input__input[disabled] { + background-color: #f0f0f0; + color: var(--jd-color-border) + } + +.jodit-ui-input__input_has-error_true { + border-color: var(--jd-color-red) +} + +.jodit-ui-input__input:focus { + outline: 0 +} + +.jodit-ui-input_theme_dark .jodit-ui-input__input { + background-color: var(--jd-color-gray) +} + +.jodit-ui-input_has-error_true .jodit-ui-input__input { + border-color: var(--jd-color-red) +} + +.jodit-ui-input__error, .jodit-ui-input__label { + color: var(--jd-color-label); + display: block; + font-size: .8em; + margin-bottom: calc(var(--jd-padding-default)/4) +} + +.jodit-ui-input__error, .jodit-ui-input_has-error_true .jodit-ui-input__label { + color: var(--jd-color-error) +} + +.jodit-ui-input__wrapper { + align-items: center; + background-color: var(--jd-color-white); + border: 1px solid var(--jd-color-border); + display: flex; + justify-content: stretch; + min-width: 200px +} + +@media (max-width:480px) { + .jodit-ui-input__wrapper { + min-width: 140px + } +} + +.jodit-ui-input_theme_dark .jodit-ui-input__wrapper { + background-color: var(--jd-color-gray); + border-color: var(--jd-color-border) +} + +.jodit-ui-input_focused_true .jodit-ui-input__wrapper { + border-color: var(--jd-color-border-selected) +} + +.jodit-ui-input__icon:not(:empty) { + align-items: center; + display: flex; + padding: 0 var(--jd-padding-default) +} + + .jodit-ui-input__icon:not(:empty) svg { + height: 16px; + width: 16px; + fill: var(--jd-color-border) + } + + .jodit-ui-input__icon:not(:empty) + .jodit-ui-input__input { + padding-left: 0 + } + +.jodit-ui-input__clear { + align-items: center; + display: flex; + opacity: .8; + padding: 0 var(--jd-padding-default) 0 0 +} + + .jodit-ui-input__clear:active { + opacity: 1; + transform: scale(1.1) + } + + .jodit-ui-input__clear svg { + height: 12px; + width: 12px; + fill: var(--jd-color-border) + } + +.jodit-ui-input_theme_dark .jodit-ui-input__clear svg, .jodit-ui-input_theme_dark .jodit-ui-input__icon svg { + fill: var(--jd-color-dark) +} + +.jodit-ui-block .jodit-ui-input { + margin-bottom: 0 +} + +.jodit-ui-select { + display: flex; + flex-direction: column; + margin-bottom: var(--jd-padding-default) +} + +.jodit-ui-select__input { + appearance: none; + background-color: var(--jd-color-white); + border: 0; + border-radius: 0; + box-sizing: border-box; + font-family: var(--jd-font-default); + font-size: var(--jd-font-size-default); + height: var(--jd-input-height); + line-height: 1.2; + outline: none; + padding: 0 var(--jd-padding-default); + width: 100% +} + + .jodit-ui-select__input[disabled] { + background-color: #f0f0f0; + color: var(--jd-color-border) + } + +.jodit-ui-select__input_has-error_true { + border-color: var(--jd-color-red) +} + +.jodit-ui-select__input:focus { + outline: 0 +} + +.jodit-ui-select_theme_dark .jodit-ui-select__input { + background-color: var(--jd-color-gray) +} + +.jodit-ui-select_has-error_true .jodit-ui-select__input { + border-color: var(--jd-color-red) +} + +.jodit-ui-select__error, .jodit-ui-select__label { + color: var(--jd-color-label); + display: block; + font-size: .8em; + margin-bottom: calc(var(--jd-padding-default)/4) +} + +.jodit-ui-select__error, .jodit-ui-select_has-error_true .jodit-ui-select__label { + color: var(--jd-color-error) +} + +.jodit-ui-select__wrapper { + align-items: center; + background-color: var(--jd-color-white); + border: 1px solid var(--jd-color-border); + display: flex; + justify-content: stretch; + min-width: 200px +} + +@media (max-width:480px) { + .jodit-ui-select__wrapper { + min-width: 140px + } +} + +.jodit-ui-select_theme_dark .jodit-ui-select__wrapper { + background-color: var(--jd-color-gray); + border-color: var(--jd-color-border) +} + +.jodit-ui-select_focused_true .jodit-ui-select__wrapper { + border-color: var(--jd-color-border-selected) +} + +.jodit-ui-select__icon:not(:empty) { + align-items: center; + display: flex; + padding: 0 var(--jd-padding-default) +} + + .jodit-ui-select__icon:not(:empty) svg { + height: 16px; + width: 16px; + fill: var(--jd-color-border) + } + + .jodit-ui-select__icon:not(:empty) + .jodit-ui-select__input { + padding-left: 0 + } + +.jodit-ui-select__clear { + align-items: center; + display: flex; + opacity: .8; + padding: 0 var(--jd-padding-default) 0 0 +} + + .jodit-ui-select__clear:active { + opacity: 1; + transform: scale(1.1) + } + + .jodit-ui-select__clear svg { + height: 12px; + width: 12px; + fill: var(--jd-color-border) + } + +.jodit-ui-select_theme_dark .jodit-ui-select__clear svg, .jodit-ui-select_theme_dark .jodit-ui-select__icon svg { + fill: var(--jd-color-dark) +} + +.jodit-ui-select__input { + background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGlkPSJMYXllcl8xIiBkYXRhLW5hbWU9IkxheWVyIDEiIHZpZXdCb3g9IjAgMCA0Ljk1IDEwIj48ZGVmcz48c3R5bGU+LmNscy0ye2ZpbGw6IzQ0NH08L3N0eWxlPjwvZGVmcz48cGF0aCBkPSJNMCAwaDQuOTV2MTBIMHoiIHN0eWxlPSJmaWxsOiNmZmYiLz48cGF0aCBkPSJtMS40MSA0LjY3IDEuMDctMS40OSAxLjA2IDEuNDl6TTMuNTQgNS4zMyAyLjQ4IDYuODIgMS40MSA1LjMzeiIgY2xhc3M9ImNscy0yIi8+PC9zdmc+); + background-position: 98% 50%; + background-repeat: no-repeat; + padding-right: calc(var(--jd-padding-default)*2) +} + +.jodit-ui-select_size_tiny { + margin-bottom: 0 +} + + .jodit-ui-select_size_tiny .jodit-ui-select__input { + --jd-height: calc(var(--jd-input-height)/1.8); + height: var(--jd-height); + line-height: var(--jd-height) + } + +.jodit-ui-select_variant_outline .jodit-ui-select__wrapper { + border: 0 +} + + .jodit-ui-select_variant_outline .jodit-ui-select__wrapper select { + outline: 0 + } + +.jodit-ui-select_width_auto { + width: auto +} + + .jodit-ui-select_width_auto .jodit-ui-select__wrapper { + min-width: auto + } + +.jodit-ui-text-area { + display: flex; + flex-direction: column; + margin-bottom: var(--jd-padding-default); + width: 100% +} + +.jodit-ui-text-area__input { + appearance: none; + background-color: var(--jd-color-white); + border: 0; + border-radius: 0; + box-sizing: border-box; + font-family: var(--jd-font-default); + font-size: var(--jd-font-size-default); + height: var(--jd-input-height); + line-height: 1.2; + outline: none; + padding: 0 var(--jd-padding-default); + width: 100% +} + + .jodit-ui-text-area__input[disabled] { + background-color: #f0f0f0; + color: var(--jd-color-border) + } + +.jodit-ui-text-area__input_has-error_true { + border-color: var(--jd-color-red) +} + +.jodit-ui-text-area__input:focus { + outline: 0 +} + +.jodit-ui-text-area_theme_dark .jodit-ui-text-area__input { + background-color: var(--jd-color-gray) +} + +.jodit-ui-text-area_has-error_true .jodit-ui-text-area__input { + border-color: var(--jd-color-red) +} + +.jodit-ui-text-area__error, .jodit-ui-text-area__label { + color: var(--jd-color-label); + display: block; + font-size: .8em; + margin-bottom: calc(var(--jd-padding-default)/4) +} + +.jodit-ui-text-area__error, .jodit-ui-text-area_has-error_true .jodit-ui-text-area__label { + color: var(--jd-color-error) +} + +.jodit-ui-text-area__wrapper { + align-items: center; + background-color: var(--jd-color-white); + border: 1px solid var(--jd-color-border); + display: flex; + justify-content: stretch; + min-width: 200px +} + +@media (max-width:480px) { + .jodit-ui-text-area__wrapper { + min-width: 140px + } +} + +.jodit-ui-text-area_theme_dark .jodit-ui-text-area__wrapper { + background-color: var(--jd-color-gray); + border-color: var(--jd-color-border) +} + +.jodit-ui-text-area_focused_true .jodit-ui-text-area__wrapper { + border-color: var(--jd-color-border-selected) +} + +.jodit-ui-text-area__icon:not(:empty) { + align-items: center; + display: flex; + padding: 0 var(--jd-padding-default) +} + + .jodit-ui-text-area__icon:not(:empty) svg { + height: 16px; + width: 16px; + fill: var(--jd-color-border) + } + + .jodit-ui-text-area__icon:not(:empty) + .jodit-ui-text-area__input { + padding-left: 0 + } + +.jodit-ui-text-area__clear { + align-items: center; + display: flex; + opacity: .8; + padding: 0 var(--jd-padding-default) 0 0 +} + + .jodit-ui-text-area__clear:active { + opacity: 1; + transform: scale(1.1) + } + + .jodit-ui-text-area__clear svg { + height: 12px; + width: 12px; + fill: var(--jd-color-border) + } + +.jodit-ui-text-area_theme_dark .jodit-ui-text-area__clear svg, .jodit-ui-text-area_theme_dark .jodit-ui-text-area__icon svg { + fill: var(--jd-color-dark) +} + +.jodit-ui-text-area__wrapper { + flex: 1 +} + +.jodit-ui-text-area__input { + height: 100%; + min-height: 60px; + padding: var(--jd-padding-default) +} + +.jodit-ui-checkbox { + align-items: center; + display: flex; + flex-direction: row-reverse; + justify-content: flex-end; + margin-bottom: var(--jd-padding-default) +} + +.jodit-ui-checkbox__input { + margin-right: var(--jd-padding-default) +} + +.jodit-ui-checkbox_switch_true .jodit-ui-checkbox__wrapper { + display: inline-block; + height: 34px; + margin-right: var(--jd-padding-default); + position: relative; + width: 60px +} + + .jodit-ui-checkbox_switch_true .jodit-ui-checkbox__wrapper input { + height: 0; + opacity: 0; + width: 0 + } + +.jodit-ui-checkbox_switch_true .jodit-ui-checkbox__switch-slider { + background-color: #ccc; + border-radius: 34px; + cursor: pointer; + inset: 0; + position: absolute; + transition: .4s +} + + .jodit-ui-checkbox_switch_true .jodit-ui-checkbox__switch-slider:before { + background-color: #fff; + border-radius: 50%; + bottom: 4px; + content: ""; + height: 26px; + left: 4px; + position: absolute; + transition: .4s; + width: 26px + } + +.jodit-ui-checkbox_switch_true.jodit-ui-checkbox_checked_true .jodit-ui-checkbox__switch-slider { + background-color: #2196f3 +} + + .jodit-ui-checkbox_switch_true.jodit-ui-checkbox_checked_true .jodit-ui-checkbox__switch-slider:before { + transform: translateX(26px) + } + +.jodit-ui-checkbox_switch_true.jodit-ui-checkbox_focused_true .jodit-ui-checkbox__switch-slider { + box-shadow: 0 0 1px #2196f3 +} + +.jodit-ui-block .jodit-ui-checkbox { + margin-bottom: 0 +} + +.jodit-ui-file-input { + overflow: hidden; + position: relative +} + +.jodit-ui-file-input__input { + bottom: 0; + cursor: pointer; + font-size: 400px; + margin: 0 calc(var(--jd-padding-default)*-1) 0 0; + opacity: 0; + padding: 0; + position: absolute; + right: 0; + top: 0 +} + +@keyframes a { + 30% { + opacity: .6 + } + + 60% { + opacity: 0 + } + + to { + opacity: .6 + } +} + +.jodit-progress-bar { + border-radius: 1px; + height: 2px; + left: 0; + opacity: .7; + position: absolute; + top: 0; + z-index: 2147483647 +} + + .jodit-progress-bar div { + background: var(--jd-color-background-progress); + height: 2px; + position: relative; + transition: width .5s ease-out,opacity .5s linear; + will-change: width,opacity + } + + .jodit-progress-bar div:after, .jodit-progress-bar div:before { + animation: a 2s ease-out 0s infinite; + border-radius: 100%; + box-shadow: var(--jd-color-background-progress) 1px 0 6px 1px; + content: ""; + display: inline-block; + height: 2px; + opacity: .6; + position: absolute; + top: 0 + } + + .jodit-progress-bar div:before { + right: -80px; + width: 180px; + clip: rect(-6px,90px,14px,-6px) + } + + .jodit-progress-bar div:after { + right: 0; + width: 20px; + clip: rect(-6px,22px,14px,var(--jd-padding-default)) + } + +:root { + --jd-em-color-border: #b6d4fe; + --jd-em-color-bg: #cfe2ff; + --jd-em-color-color: #084298; + --jd-em-border-radius: 0.375rem; + --jd-em-padding: 0.5rem 1rem; + --jd-em-font-size: 1rem +} + +.jodit-ui-messages { + bottom: 0; + height: 0; + overflow: visible; + position: absolute; + right: 0; + width: 0; + z-index: 3 +} + +.jodit-ui-message { + background: var(--jd-em-color-bg); + border: 1px solid var(--jd-em-color-border); + border-radius: var(--jd-em-border-radius); + bottom: 0; + color: var(--jd-em-color-color); + cursor: pointer; + display: block; + font-size: var(--jd-em-font-size); + opacity: 0; + padding: var(--jd-em-padding); + position: absolute; + right: calc(var(--jd-padding-default)/2); + transition: opacity .1s linear,bottom .3s linear,transform .1s ease-out; + white-space: pre +} + +.jodit-ui-message_active_true { + opacity: 1 +} + +.jodit-ui-message:active { + transform: scale(.76) +} + +.jodit-ui-message_variant_secondary { + --jd-em-color-border: #d3d6d8; + --jd-em-color-bg: #e2e3e5; + --jd-em-color-color: #41464b +} + +.jodit-ui-message_variant_danger, .jodit-ui-message_variant_error, .jodit-ui-message_variant_secondary { + background: var(--jd-em-color-bg); + border-color: var(--jd-em-color-border); + color: var(--jd-em-color-color) +} + +.jodit-ui-message_variant_danger, .jodit-ui-message_variant_error { + --jd-em-color-border: #f5c2c7; + --jd-em-color-bg: #f8d7da; + --jd-em-color-color: #842029 +} + +.jodit-ui-message_variant_success { + --jd-em-color-border: #badbcc; + --jd-em-color-bg: #d1e7dd; + --jd-em-color-color: #0f5132; + background: var(--jd-em-color-bg); + border-color: var(--jd-em-color-border); + color: var(--jd-em-color-color) +} + +.jodit-toolbar-collection, .jodit-toolbar-editor-collection { + display: flex; + flex-direction: column +} + +.jodit-toolbar-collection_mode_horizontal, .jodit-toolbar-editor-collection_mode_horizontal { + background-image: repeating-linear-gradient(transparent 0,transparent calc(var(--jd-button-size) - 1px),var(--jd-color-border) var(--jd-button-size)); + position: relative +} + + .jodit-toolbar-collection_mode_horizontal:after, .jodit-toolbar-editor-collection_mode_horizontal:after { + background-color: var(--jd-color-background-default); + bottom: 0; + content: ""; + display: block; + height: 1px; + left: 0; + position: absolute; + width: 100% + } + +.jodit-toolbar-collection_size_tiny, .jodit-toolbar-editor-collection_size_tiny { + --jd-button-icon-size: 8px +} + + .jodit-toolbar-collection_size_tiny.jodit-toolbar-collection_mode_horizontal, .jodit-toolbar-collection_size_tiny.jodit-toolbar-editor-collection_mode_horizontal, .jodit-toolbar-editor-collection_size_tiny.jodit-toolbar-collection_mode_horizontal, .jodit-toolbar-editor-collection_size_tiny.jodit-toolbar-editor-collection_mode_horizontal { + background-image: repeating-linear-gradient(transparent 0,transparent 19px,var(--jd-color-border) 20px) + } + +.jodit-toolbar-collection_size_xsmall, .jodit-toolbar-editor-collection_size_xsmall { + --jd-button-icon-size: 10px +} + + .jodit-toolbar-collection_size_xsmall.jodit-toolbar-collection_mode_horizontal, .jodit-toolbar-collection_size_xsmall.jodit-toolbar-editor-collection_mode_horizontal, .jodit-toolbar-editor-collection_size_xsmall.jodit-toolbar-collection_mode_horizontal, .jodit-toolbar-editor-collection_size_xsmall.jodit-toolbar-editor-collection_mode_horizontal { + background-image: repeating-linear-gradient(transparent 0,transparent 25px,var(--jd-color-border) 26px) + } + +.jodit-toolbar-collection_size_small, .jodit-toolbar-editor-collection_size_small { + --jd-button-icon-size: 12px +} + + .jodit-toolbar-collection_size_small.jodit-toolbar-collection_mode_horizontal, .jodit-toolbar-collection_size_small.jodit-toolbar-editor-collection_mode_horizontal, .jodit-toolbar-editor-collection_size_small.jodit-toolbar-collection_mode_horizontal, .jodit-toolbar-editor-collection_size_small.jodit-toolbar-editor-collection_mode_horizontal { + background-image: repeating-linear-gradient(transparent 0,transparent 31px,var(--jd-color-border) 32px) + } + +.jodit-toolbar-collection_size_middle, .jodit-toolbar-editor-collection_size_middle { + --jd-button-icon-size: 14px +} + + .jodit-toolbar-collection_size_middle.jodit-toolbar-collection_mode_horizontal, .jodit-toolbar-collection_size_middle.jodit-toolbar-editor-collection_mode_horizontal, .jodit-toolbar-editor-collection_size_middle.jodit-toolbar-collection_mode_horizontal, .jodit-toolbar-editor-collection_size_middle.jodit-toolbar-editor-collection_mode_horizontal { + background-image: repeating-linear-gradient(transparent 0,transparent 37px,var(--jd-color-border) 38px) + } + +.jodit-toolbar-collection_size_large, .jodit-toolbar-editor-collection_size_large { + --jd-button-icon-size: 16px +} + + .jodit-toolbar-collection_size_large.jodit-toolbar-collection_mode_horizontal, .jodit-toolbar-collection_size_large.jodit-toolbar-editor-collection_mode_horizontal, .jodit-toolbar-editor-collection_size_large.jodit-toolbar-collection_mode_horizontal, .jodit-toolbar-editor-collection_size_large.jodit-toolbar-editor-collection_mode_horizontal { + background-image: repeating-linear-gradient(transparent 0,transparent 43px,var(--jd-color-border) 44px) + } + +.jodit-toolbar-collection_mode_vertical .jodit-ui-group, .jodit-toolbar-editor-collection_mode_vertical .jodit-ui-group { + background-color: transparent; + border: 0; + flex-direction: column +} + +.jodit-toolbar-collection_mode_vertical .jodit-toolbar-button, .jodit-toolbar-editor-collection_mode_vertical .jodit-toolbar-button { + height: auto; + min-height: var(--jd-button-size) +} + +.jodit-toolbar-collection_mode_vertical .jodit-toolbar-button__button, .jodit-toolbar-editor-collection_mode_vertical .jodit-toolbar-button__button { + cursor: pointer; + height: auto; + min-height: var(--jd-button-size); + width: 100% +} + +.jodit-toolbar-collection_mode_vertical .jodit-toolbar-button__text:not(:empty), .jodit-toolbar-editor-collection_mode_vertical .jodit-toolbar-button__text:not(:empty) { + justify-content: left +} + +.jodit-toolbar-collection .jodit-toolbar-button, .jodit-toolbar-collection .jodit-toolbar-content, .jodit-toolbar-collection .jodit-toolbar-select, .jodit-toolbar-editor-collection .jodit-toolbar-button, .jodit-toolbar-editor-collection .jodit-toolbar-content, .jodit-toolbar-editor-collection .jodit-toolbar-select { + margin: var(--jd-margin-v) 1px; + padding: 0 +} + +.jodit-dialog .jodit-toolbar-collection_mode_horizontal, .jodit-dialog .jodit-toolbar-editor-collection_mode_horizontal { + background-image: none +} + +:root { + --jd-button-trigger-size: 14px +} + +.jodit-toolbar-button { + align-items: center; + border: 1px solid transparent; + border-radius: var(--jd-border-radius-default); + display: flex; + height: 34px; + justify-content: center; + min-width: 34px; + overflow: hidden +} + +.jodit-toolbar-button__icon { + display: none +} + + .jodit-toolbar-button__icon:not(:empty) { + display: inline-flex + } + +.jodit-toolbar-button__text { + display: none +} + + .jodit-toolbar-button__text:not(:empty) { + display: inline-flex; + flex-grow: 1; + font-family: var(--jd-font-default); + font-size: var(--jd-font-size-default); + justify-content: center + } + +.jodit-toolbar-button_context_menu .jodit-toolbar-button__text { + justify-content: left; + padding-left: var(--jd-padding-default); + position: relative +} + + .jodit-toolbar-button_context_menu .jodit-toolbar-button__text:before { + border-left: 1px solid var(--jd-color-border); + content: ""; + height: 35px; + left: 0; + position: absolute; + top: calc(var(--jd-padding-default)*-1) + } + +.jodit-toolbar-button__icon:not(:empty) + .jodit-toolbar-button__text:not(:empty) { + margin-left: var(--jd-padding-default) +} + +.jodit-toolbar-button__icon:empty + .jodit-toolbar-button__text:not(:empty) { + padding: 0 var(--jd-padding-default); + padding: 0 +} + +.jodit-toolbar-button .jodit-icon { + height: 14px; + width: 14px +} + +.jodit-toolbar-button button { + appearance: none; + height: 34px; + min-width: 34px; + padding: 0 +} + +.jodit-toolbar-button_text-icons_true button { + padding: 0 var(--jd-padding-default) +} + +.jodit-toolbar-button_size_tiny { + height: 16px; + min-width: 16px +} + + .jodit-toolbar-button_size_tiny .jodit-icon { + height: 8px; + width: 8px + } + + .jodit-toolbar-button_size_tiny button { + appearance: none; + height: 16px; + min-width: 16px; + padding: 0 + } + +.jodit-toolbar-button_size_tiny_text-icons_true button { + padding: 0 var(--jd-padding-default) +} + +.jodit-toolbar-button_size_xsmall { + height: 22px; + min-width: 22px +} + + .jodit-toolbar-button_size_xsmall .jodit-icon { + height: 10px; + width: 10px + } + + .jodit-toolbar-button_size_xsmall button { + appearance: none; + height: 22px; + min-width: 22px; + padding: 0 + } + +.jodit-toolbar-button_size_xsmall_text-icons_true button { + padding: 0 var(--jd-padding-default) +} + +.jodit-toolbar-button_size_small { + height: 28px; + min-width: 28px +} + + .jodit-toolbar-button_size_small .jodit-icon { + height: 12px; + width: 12px + } + + .jodit-toolbar-button_size_small button { + appearance: none; + height: 28px; + min-width: 28px; + padding: 0 + } + +.jodit-toolbar-button_size_small_text-icons_true button { + padding: 0 var(--jd-padding-default) +} + +.jodit-toolbar-button_size_large { + height: 40px; + min-width: 40px +} + + .jodit-toolbar-button_size_large .jodit-icon { + height: 16px; + width: 16px + } + + .jodit-toolbar-button_size_large button { + appearance: none; + height: 40px; + min-width: 40px; + padding: 0 + } + +.jodit-toolbar-button_size_large_text-icons_true button { + padding: 0 var(--jd-padding-default) +} + +.jodit-toolbar-button__button { + align-items: center; + appearance: none; + background: 0 0; + border: 0; + border-radius: var(--jd-border-radius-default); + box-shadow: none; + box-sizing: border-box; + color: var(--jd-color-text-icons); + cursor: pointer; + display: inline-flex; + font-style: normal; + justify-content: center; + outline: 0; + padding: 0; + padding: 0 var(--jd-padding-default); + position: relative; + text-align: center; + text-decoration: none; + text-transform: none; + user-select: none +} + + .jodit-toolbar-button__button:focus-visible:not([disabled]), .jodit-toolbar-button__button:hover:not([disabled]) { + background-color: var(--jd-color-button-background-hover); + opacity: 1; + outline: 0 + } + + .jodit-toolbar-button__button:active:not([disabled]), .jodit-toolbar-button__button[aria-pressed=true]:not([disabled]) { + background-color: var(--jd-color-button-background-hover-opacity40); + outline: 0 + } + + .jodit-toolbar-button__button[aria-pressed=true]:hover:not([disabled]) { + background-color: var(--jd-color-button-background-hover-opacity60) + } + + .jodit-toolbar-button__button[disabled] { + opacity: .3; + pointer-events: none + } + +.jodit-toolbar-button__trigger { + align-items: center; + border-radius: 0 var(--jd-border-radius-default) var(--jd-border-radius-default) 0; + cursor: pointer; + display: flex; + height: 100%; + justify-content: center; + opacity: .4; + --jd-button-trigger-size: 14px; + width: calc(var(--jd-button-trigger-size, 14px) + 2px) +} + + .jodit-toolbar-button__trigger:focus-visible:not([disabled]), .jodit-toolbar-button__trigger:hover:not([disabled]) { + background-color: var(--jd-color-button-background-hover); + opacity: 1; + outline: 0 + } + + .jodit-toolbar-button__trigger:active:not([disabled]), .jodit-toolbar-button__trigger[aria-pressed=true]:not([disabled]) { + background-color: var(--jd-color-button-background-hover-opacity40); + outline: 0 + } + + .jodit-toolbar-button__trigger[aria-pressed=true]:hover:not([disabled]) { + background-color: var(--jd-color-button-background-hover-opacity60) + } + + .jodit-toolbar-button__trigger[disabled] { + opacity: .3; + pointer-events: none + } + + .jodit-toolbar-button__trigger svg { + width: calc(var(--jd-button-trigger-size, 14px) - 4px) + } + +.jodit-toolbar-button_size_tiny .jodit-toolbar-button__trigger { + --jd-button-trigger-size: 8px; + width: calc(var(--jd-button-trigger-size, 8px) + 2px) +} + + .jodit-toolbar-button_size_tiny .jodit-toolbar-button__trigger svg { + width: calc(var(--jd-button-trigger-size, 8px) - 4px) + } + +.jodit-toolbar-button_size_xsmall .jodit-toolbar-button__trigger { + --jd-button-trigger-size: 10px; + width: calc(var(--jd-button-trigger-size, 10px) + 2px) +} + + .jodit-toolbar-button_size_xsmall .jodit-toolbar-button__trigger svg { + width: calc(var(--jd-button-trigger-size, 10px) - 4px) + } + +.jodit-toolbar-button_size_small .jodit-toolbar-button__trigger { + --jd-button-trigger-size: 12px; + width: calc(var(--jd-button-trigger-size, 12px) + 2px) +} + + .jodit-toolbar-button_size_small .jodit-toolbar-button__trigger svg { + width: calc(var(--jd-button-trigger-size, 12px) - 4px) + } + +.jodit-toolbar-button_size_large .jodit-toolbar-button__trigger { + --jd-button-trigger-size: 16px; + width: calc(var(--jd-button-trigger-size, 16px) + 2px) +} + + .jodit-toolbar-button_size_large .jodit-toolbar-button__trigger svg { + width: calc(var(--jd-button-trigger-size, 16px) - 4px) + } + +.jodit-toolbar-button_with-trigger_true .jodit-toolbar-button__button { + border-radius: var(--jd-border-radius-default) 0 0 var(--jd-border-radius-default) +} + +.jodit-toolbar-button_with-trigger_true:hover:not([disabled]) { + border-color: var(--jd-color-border) +} + +.jodit-toolbar-button_stroke_false svg { + stroke: none +} + +.jodit-toolbar-content { + align-items: center; + appearance: none; + background: 0 0; + border: 1px solid transparent; + border-radius: var(--jd-border-radius-default); + box-shadow: none; + box-sizing: border-box; + color: var(--jd-color-text-icons); + cursor: pointer; + display: inline-flex; + font-style: normal; + height: 34px; + justify-content: center; + min-width: 34px; + outline: 0; + padding: 0; + position: relative; + text-align: center; + text-decoration: none; + text-transform: none; + user-select: none +} + + .jodit-toolbar-content:focus-visible:not([disabled]), .jodit-toolbar-content:hover:not([disabled]) { + background-color: var(--jd-color-button-background-hover); + opacity: 1; + outline: 0 + } + + .jodit-toolbar-content:active:not([disabled]), .jodit-toolbar-content[aria-pressed=true]:not([disabled]) { + background-color: var(--jd-color-button-background-hover-opacity40); + outline: 0 + } + + .jodit-toolbar-content[aria-pressed=true]:hover:not([disabled]) { + background-color: var(--jd-color-button-background-hover-opacity60) + } + + .jodit-toolbar-content[disabled] { + opacity: .3; + pointer-events: none + } + + .jodit-toolbar-content .jodit-icon { + height: 14px; + width: 14px + } + + .jodit-toolbar-content button { + appearance: none; + height: 34px; + min-width: 34px; + padding: 0 + } + +.jodit-toolbar-content_text-icons_true button { + padding: 0 var(--jd-padding-default) +} + +.jodit-toolbar-content_size_tiny { + height: 16px; + min-width: 16px +} + + .jodit-toolbar-content_size_tiny .jodit-icon { + height: 8px; + width: 8px + } + + .jodit-toolbar-content_size_tiny button { + appearance: none; + height: 16px; + min-width: 16px; + padding: 0 + } + +.jodit-toolbar-content_size_tiny_text-icons_true button { + padding: 0 var(--jd-padding-default) +} + +.jodit-toolbar-content_size_xsmall { + height: 22px; + min-width: 22px +} + + .jodit-toolbar-content_size_xsmall .jodit-icon { + height: 10px; + width: 10px + } + + .jodit-toolbar-content_size_xsmall button { + appearance: none; + height: 22px; + min-width: 22px; + padding: 0 + } + +.jodit-toolbar-content_size_xsmall_text-icons_true button { + padding: 0 var(--jd-padding-default) +} + +.jodit-toolbar-content_size_small { + height: 28px; + min-width: 28px +} + + .jodit-toolbar-content_size_small .jodit-icon { + height: 12px; + width: 12px + } + + .jodit-toolbar-content_size_small button { + appearance: none; + height: 28px; + min-width: 28px; + padding: 0 + } + +.jodit-toolbar-content_size_small_text-icons_true button { + padding: 0 var(--jd-padding-default) +} + +.jodit-toolbar-content_size_large { + height: 40px; + min-width: 40px +} + + .jodit-toolbar-content_size_large .jodit-icon { + height: 16px; + width: 16px + } + + .jodit-toolbar-content_size_large button { + appearance: none; + height: 40px; + min-width: 40px; + padding: 0 + } + +.jodit-toolbar-content_size_large_text-icons_true button { + padding: 0 var(--jd-padding-default) +} + +.jodit-toolbar-content__icon { + display: none +} + + .jodit-toolbar-content__icon:not(:empty) { + display: inline-flex + } + +.jodit-toolbar-content__text { + display: none +} + + .jodit-toolbar-content__text:not(:empty) { + display: inline-flex; + flex-grow: 1; + font-family: var(--jd-font-default); + font-size: var(--jd-font-size-default); + justify-content: center + } + +.jodit-toolbar-content_context_menu .jodit-toolbar-content__text { + justify-content: left; + padding-left: var(--jd-padding-default); + position: relative +} + + .jodit-toolbar-content_context_menu .jodit-toolbar-content__text:before { + border-left: 1px solid var(--jd-color-border); + content: ""; + height: 35px; + left: 0; + position: absolute; + top: calc(var(--jd-padding-default)*-1) + } + +.jodit-toolbar-content__icon:not(:empty) + .jodit-toolbar-content__text:not(:empty) { + margin-left: var(--jd-padding-default) +} + +.jodit-toolbar-content__icon:empty + .jodit-toolbar-content__text:not(:empty) { + padding: 0 var(--jd-padding-default) +} + +.jodit-toolbar-content:focus:not([disabled]) { + outline: 1px dashed var(--jd-color-background-selection) +} + +.jodit-toolbar-content_variant_outline { + border: 1px solid var(--jd-color-border) +} + +.jodit-toolbar-content_variant_default { + background-color: #e3e3e3; + color: #212529 +} + + .jodit-toolbar-content_variant_default svg { + fill: #212529; + stroke: #212529 + } + + .jodit-toolbar-content_variant_default [disabled] { + opacity: .7 + } + + .jodit-toolbar-content_variant_default:hover:not([disabled]) { + background-color: #c9cdd1; + color: #212529 + } + + .jodit-toolbar-content_variant_default:hover:not([disabled]) svg { + fill: #212529; + stroke: #212529 + } + + .jodit-toolbar-content_variant_default:active:not([disabled]) { + background-color: #dae0e5; + color: #212529 + } + + .jodit-toolbar-content_variant_default:active:not([disabled]) svg { + fill: #212529; + stroke: #212529 + } + + .jodit-toolbar-content_variant_default:focus:not([disabled]) { + outline: 1px dashed #dae0e5 + } + +.jodit-toolbar-content_variant_primary { + background-color: #007bff; + color: #fff +} + + .jodit-toolbar-content_variant_primary svg { + fill: #fff; + stroke: #fff + } + + .jodit-toolbar-content_variant_primary [disabled] { + opacity: .7 + } + + .jodit-toolbar-content_variant_primary:hover:not([disabled]) { + background-color: #0069d9; + color: #fff + } + + .jodit-toolbar-content_variant_primary:hover:not([disabled]) svg { + fill: #fff; + stroke: #fff + } + + .jodit-toolbar-content_variant_primary:active:not([disabled]) { + background-color: #0062cc; + color: #fff + } + + .jodit-toolbar-content_variant_primary:active:not([disabled]) svg { + fill: #fff; + stroke: #fff + } + + .jodit-toolbar-content_variant_primary:focus:not([disabled]) { + outline: 1px dashed #0062cc + } + +.jodit-toolbar-content_variant_secondary { + background-color: #d8d8d8; + border-radius: 0; + color: #212529 +} + + .jodit-toolbar-content_variant_secondary svg { + fill: #212529; + stroke: #212529 + } + + .jodit-toolbar-content_variant_secondary [disabled] { + opacity: .7 + } + + .jodit-toolbar-content_variant_secondary:hover:not([disabled]) { + background-color: #c9cdd1; + color: #212529 + } + + .jodit-toolbar-content_variant_secondary:hover:not([disabled]) svg { + fill: #212529; + stroke: #212529 + } + + .jodit-toolbar-content_variant_secondary:active:not([disabled]) { + background-color: #dae0e5; + color: #212529 + } + + .jodit-toolbar-content_variant_secondary:active:not([disabled]) svg { + fill: #212529; + stroke: #212529 + } + + .jodit-toolbar-content_variant_secondary:focus:not([disabled]) { + outline: 1px dashed #dae0e5 + } + +.jodit-toolbar-content_variant_success { + background-color: #28a745; + color: #fff +} + + .jodit-toolbar-content_variant_success svg { + fill: #fff; + stroke: #fff + } + + .jodit-toolbar-content_variant_success [disabled] { + opacity: .7 + } + + .jodit-toolbar-content_variant_success:hover:not([disabled]) { + background-color: #218838; + color: #fff + } + + .jodit-toolbar-content_variant_success:hover:not([disabled]) svg { + fill: #fff; + stroke: #fff + } + + .jodit-toolbar-content_variant_success:active:not([disabled]) { + background-color: #1e7e34; + color: #fff + } + + .jodit-toolbar-content_variant_success:active:not([disabled]) svg { + fill: #fff; + stroke: #fff + } + + .jodit-toolbar-content_variant_success:focus:not([disabled]) { + outline: 1px dashed #1e7e34 + } + +.jodit-toolbar-content_variant_danger { + background-color: #dc3545; + color: #fff +} + + .jodit-toolbar-content_variant_danger svg { + fill: #fff; + stroke: #fff + } + + .jodit-toolbar-content_variant_danger [disabled] { + opacity: .7 + } + + .jodit-toolbar-content_variant_danger:hover:not([disabled]) { + background-color: #c82333; + color: #fff + } + + .jodit-toolbar-content_variant_danger:hover:not([disabled]) svg { + fill: #fff; + stroke: #fff + } + + .jodit-toolbar-content_variant_danger:active:not([disabled]) { + background-color: #bd2130; + color: #fff + } + + .jodit-toolbar-content_variant_danger:active:not([disabled]) svg { + fill: #fff; + stroke: #fff + } + + .jodit-toolbar-content_variant_danger:focus:not([disabled]) { + outline: 1px dashed #bd2130 + } + +.jodit-toolbar-content:hover:not([disabled]) { + background-color: transparent; + opacity: 1; + outline: 0 +} + +.jodit-toolbar-select { + --jd-color-button-background-hover-opacity40: hsla(0,0%,86%,.2); + --jd-color-button-background-hover-opacity60: hsla(0,0%,86%,.1); + align-items: center; + border: 1px solid transparent; + border-radius: var(--jd-border-radius-default); + cursor: pointer; + display: flex; + height: 34px; + justify-content: center; + justify-content: space-between; + min-width: 34px; + min-width: 100px; + overflow: hidden +} + +.jodit-toolbar-select__icon { + display: none +} + + .jodit-toolbar-select__icon:not(:empty) { + display: inline-flex + } + +.jodit-toolbar-select__text { + display: none +} + + .jodit-toolbar-select__text:not(:empty) { + display: inline-flex; + flex-grow: 1; + font-family: var(--jd-font-default); + font-size: var(--jd-font-size-default); + justify-content: center + } + +.jodit-toolbar-select_context_menu .jodit-toolbar-select__text { + justify-content: left; + padding-left: var(--jd-padding-default); + position: relative +} + + .jodit-toolbar-select_context_menu .jodit-toolbar-select__text:before { + border-left: 1px solid var(--jd-color-border); + content: ""; + height: 35px; + left: 0; + position: absolute; + top: calc(var(--jd-padding-default)*-1) + } + +.jodit-toolbar-select__icon:not(:empty) + .jodit-toolbar-select__text:not(:empty) { + margin-left: var(--jd-padding-default) +} + +.jodit-toolbar-select__icon:empty + .jodit-toolbar-select__text:not(:empty) { + padding: 0 var(--jd-padding-default); + padding: 0 +} + +.jodit-toolbar-select .jodit-icon { + height: 14px; + width: 14px +} + +.jodit-toolbar-select button { + appearance: none; + height: 34px; + min-width: 34px; + padding: 0 +} + +.jodit-toolbar-select_text-icons_true button { + padding: 0 var(--jd-padding-default) +} + +.jodit-toolbar-select_size_tiny { + height: 16px; + min-width: 16px +} + + .jodit-toolbar-select_size_tiny .jodit-icon { + height: 8px; + width: 8px + } + + .jodit-toolbar-select_size_tiny button { + appearance: none; + height: 16px; + min-width: 16px; + padding: 0 + } + +.jodit-toolbar-select_size_tiny_text-icons_true button { + padding: 0 var(--jd-padding-default) +} + +.jodit-toolbar-select_size_xsmall { + height: 22px; + min-width: 22px +} + + .jodit-toolbar-select_size_xsmall .jodit-icon { + height: 10px; + width: 10px + } + + .jodit-toolbar-select_size_xsmall button { + appearance: none; + height: 22px; + min-width: 22px; + padding: 0 + } + +.jodit-toolbar-select_size_xsmall_text-icons_true button { + padding: 0 var(--jd-padding-default) +} + +.jodit-toolbar-select_size_small { + height: 28px; + min-width: 28px +} + + .jodit-toolbar-select_size_small .jodit-icon { + height: 12px; + width: 12px + } + + .jodit-toolbar-select_size_small button { + appearance: none; + height: 28px; + min-width: 28px; + padding: 0 + } + +.jodit-toolbar-select_size_small_text-icons_true button { + padding: 0 var(--jd-padding-default) +} + +.jodit-toolbar-select_size_large { + height: 40px; + min-width: 40px +} + + .jodit-toolbar-select_size_large .jodit-icon { + height: 16px; + width: 16px + } + + .jodit-toolbar-select_size_large button { + appearance: none; + height: 40px; + min-width: 40px; + padding: 0 + } + +.jodit-toolbar-select_size_large_text-icons_true button { + padding: 0 var(--jd-padding-default) +} + +.jodit-toolbar-select__button { + align-items: center; + appearance: none; + background: 0 0; + border: 0; + border-radius: var(--jd-border-radius-default); + box-shadow: none; + box-sizing: border-box; + color: var(--jd-color-text-icons); + cursor: pointer; + display: inline-flex; + font-style: normal; + justify-content: center; + outline: 0; + padding: 0; + padding: 0 var(--jd-padding-default); + position: relative; + text-align: center; + text-decoration: none; + text-transform: none; + user-select: none +} + + .jodit-toolbar-select__button:focus-visible:not([disabled]), .jodit-toolbar-select__button:hover:not([disabled]) { + background-color: var(--jd-color-button-background-hover); + opacity: 1; + outline: 0 + } + + .jodit-toolbar-select__button:active:not([disabled]), .jodit-toolbar-select__button[aria-pressed=true]:not([disabled]) { + background-color: var(--jd-color-button-background-hover-opacity40); + outline: 0 + } + + .jodit-toolbar-select__button[aria-pressed=true]:hover:not([disabled]) { + background-color: var(--jd-color-button-background-hover-opacity60) + } + + .jodit-toolbar-select__button[disabled] { + opacity: .3; + pointer-events: none + } + +.jodit-toolbar-select__trigger { + align-items: center; + border-radius: 0 var(--jd-border-radius-default) var(--jd-border-radius-default) 0; + cursor: pointer; + display: flex; + height: 100%; + justify-content: center; + opacity: .4; + --jd-button-trigger-size: 14px; + width: calc(var(--jd-button-trigger-size, 14px) + 2px) +} + + .jodit-toolbar-select__trigger:focus-visible:not([disabled]), .jodit-toolbar-select__trigger:hover:not([disabled]) { + background-color: var(--jd-color-button-background-hover); + opacity: 1; + outline: 0 + } + + .jodit-toolbar-select__trigger:active:not([disabled]), .jodit-toolbar-select__trigger[aria-pressed=true]:not([disabled]) { + background-color: var(--jd-color-button-background-hover-opacity40); + outline: 0 + } + + .jodit-toolbar-select__trigger[aria-pressed=true]:hover:not([disabled]) { + background-color: var(--jd-color-button-background-hover-opacity60) + } + + .jodit-toolbar-select__trigger[disabled] { + opacity: .3; + pointer-events: none + } + + .jodit-toolbar-select__trigger svg { + width: calc(var(--jd-button-trigger-size, 14px) - 4px) + } + +.jodit-toolbar-select_size_tiny .jodit-toolbar-select__trigger { + --jd-button-trigger-size: 8px; + width: calc(var(--jd-button-trigger-size, 8px) + 2px) +} + + .jodit-toolbar-select_size_tiny .jodit-toolbar-select__trigger svg { + width: calc(var(--jd-button-trigger-size, 8px) - 4px) + } + +.jodit-toolbar-select_size_xsmall .jodit-toolbar-select__trigger { + --jd-button-trigger-size: 10px; + width: calc(var(--jd-button-trigger-size, 10px) + 2px) +} + + .jodit-toolbar-select_size_xsmall .jodit-toolbar-select__trigger svg { + width: calc(var(--jd-button-trigger-size, 10px) - 4px) + } + +.jodit-toolbar-select_size_small .jodit-toolbar-select__trigger { + --jd-button-trigger-size: 12px; + width: calc(var(--jd-button-trigger-size, 12px) + 2px) +} + + .jodit-toolbar-select_size_small .jodit-toolbar-select__trigger svg { + width: calc(var(--jd-button-trigger-size, 12px) - 4px) + } + +.jodit-toolbar-select_size_large .jodit-toolbar-select__trigger { + --jd-button-trigger-size: 16px; + width: calc(var(--jd-button-trigger-size, 16px) + 2px) +} + + .jodit-toolbar-select_size_large .jodit-toolbar-select__trigger svg { + width: calc(var(--jd-button-trigger-size, 16px) - 4px) + } + +.jodit-toolbar-select_with-trigger_true .jodit-toolbar-button__button { + border-radius: var(--jd-border-radius-default) 0 0 var(--jd-border-radius-default) +} + +.jodit-toolbar-select_with-trigger_true:hover:not([disabled]) { + border-color: var(--jd-color-border) +} + +.jodit-toolbar-select_stroke_false svg { + stroke: none +} + +.jodit-toolbar-select:focus-visible:not([disabled]), .jodit-toolbar-select:hover:not([disabled]) { + background-color: var(--jd-color-button-background-hover); + opacity: 1; + outline: 0 +} + +.jodit-toolbar-select:active:not([disabled]), .jodit-toolbar-select[aria-pressed=true]:not([disabled]) { + background-color: var(--jd-color-button-background-hover-opacity40); + outline: 0 +} + +.jodit-toolbar-select[aria-pressed=true]:hover:not([disabled]) { + background-color: var(--jd-color-button-background-hover-opacity60) +} + +.jodit-toolbar-select[disabled] { + opacity: .3; + pointer-events: none +} + +.jodit-toolbar-select__text:not(:empty) { + justify-content: left +} + +.jodit-toolbar-select__button { + flex: 1 +} + +.jodit-toolbar__box:not(:empty) { + --jd-color-background-default: var(--jd-color-panel); + background-color: var(--jd-color-background-default); + border-bottom: 1px solid var(--jd-color-border); + border-radius: var(--jd-border-radius-default) var(--jd-border-radius-default) 0 0; + overflow: hidden +} + + .jodit-toolbar__box:not(:empty) .jodit-toolbar-editor-collection:after { + background-color: var(--jd-color-panel) + } + +.jodit-dialog { + border: 0; + box-sizing: border-box; + display: none; + font-family: var(--jd-font-default); + font-size: var(--jd-font-size-default); + height: 0; + position: absolute; + width: 0; + will-change: left,top,width,height +} + +.jodit-dialog_moved_true { + user-select: none +} + +.jodit-dialog * { + box-sizing: border-box +} + +.jodit-dialog .jodit_elfinder, .jodit-dialog .jodit_elfinder * { + box-sizing: initial +} + +.jodit-dialog__overlay { + background-color: rgba(0,0,0,.5); + display: none; + height: 100%; + left: 0; + overflow: auto; + position: fixed; + text-align: center; + top: 0; + white-space: nowrap; + width: 100%; + z-index: var(--jd-z-index-dialog-overlay) +} + +.jodit-dialog_static_true .jodit-dialog__overlay { + display: none +} + +.jodit-dialog_active_true, .jodit-dialog_modal_true .jodit-dialog__overlay { + display: block +} + +.jodit-dialog__panel { + background-color: #fff; + display: flex; + flex-flow: column nowrap; + left: 0; + max-height: 100%; + max-width: 100%; + min-height: 100px; + min-width: 200px; + position: fixed; + top: 0; + z-index: var(--jd-z-index-dialog); + --jd-box-shadow-blur: calc(var(--jd-padding-default)*2); + --jd-box-shadow-1: 0 var(--jd-padding-default) var(--jd-box-shadow-blur) rgba(0,0,0,.19); + box-shadow: var(--jd-box-shadow-1),0 6px 6px rgba(0,0,0,.23); + text-align: left; + white-space: normal +} + +@media (max-width:480px) { + .jodit-dialog:not(.jodit-dialog_adaptive_false) .jodit-dialog__panel { + height: 100% !important; + left: 0 !important; + max-width: 100%; + top: 0 !important; + width: 100% !important + } +} + +.jodit-dialog_static_true { + box-sizing: border-box; + display: block; + height: auto; + position: relative; + width: auto; + z-index: inherit +} + + .jodit-dialog_static_true .jodit-dialog__panel { + border: 1px solid var(--jd-color-border); + box-shadow: none; + left: auto !important; + position: relative; + top: auto !important; + width: 100% !important; + z-index: inherit + } + +.jodit-dialog_theme_dark, .jodit-dialog_theme_dark .jodit-dialog__panel { + background-color: var(--jd-dark-background-darknes); + color: var(--jd-dark-text-color) +} + +.jodit-dialog__header { + border-bottom: 1px solid var(--jd-color-border); + cursor: move; + display: flex; + justify-content: space-between; + min-height: 50px; + text-align: left +} + +.jodit-dialog__header-title, .jodit-dialog__header-toolbar { + align-items: center; + display: flex; + flex-shrink: 3; + font-size: 18px; + font-weight: 400; + line-height: 48px; + margin: 0; + padding: 0 var(--jd-padding-default); + vertical-align: top +} + +@media (max-width:480px) { + .jodit-dialog__header-toolbar { + padding-left: 0 + } +} + +.jodit-dialog__header-button { + color: #222; + flex-basis: 48px; + font-size: 28px; + height: 48px; + line-height: 48px; + text-align: center; + text-decoration: none; + transition: background-color .2s ease 0s +} + + .jodit-dialog__header-button:hover { + background-color: var(--jd-color-background-button-hover) + } + +.jodit-dialog__header .jodit_toolbar { + background: transparent; + border: 0; + box-shadow: none +} + + .jodit-dialog__header .jodit_toolbar > li.jodit-toolbar-button .jodit-input { + padding-left: var(--jd-padding-default); + width: auto + } + +@media (max-width:480px) { + .jodit-dialog:not(.jodit-dialog_adaptive_false) .jodit-dialog__header { + flex-direction: column + } +} + +.jodit-dialog_slim_true .jodit-dialog__header { + min-height: 10px +} + +.jodit-dialog_slim_true .jodit-dialog__header-title, .jodit-dialog_slim_true .jodit-dialog__header-toolbar { + padding: 0 calc(var(--jd-padding-default)/4) +} + +.jodit-dialog_theme_dark .jodit-dialog__header { + border-color: var(--jd-color-dark) +} + +.jodit-dialog_fullsize_true .jodit-dialog__header { + cursor: default +} + +.jodit-dialog__content { + flex: 1; + min-height: 100px; + overflow: auto +} + + .jodit-dialog__content .jodit-form__group { + margin-bottom: calc(var(--jd-padding-default)*1.5); + padding: 0 var(--jd-padding-default) + } + + .jodit-dialog__content .jodit-form__group:first-child { + margin-top: var(--jd-padding-default) + } + + .jodit-dialog__content .jodit-form__group .jodit-input_group { + border-collapse: separate; + display: table; + width: 100% + } + + .jodit-dialog__content .jodit-form__group .jodit-input_group > * { + display: table-cell; + height: 34px; + vertical-align: middle + } + + .jodit-dialog__content .jodit-form__group .jodit-input_group > input { + margin: 0 !important + } + + .jodit-dialog__content .jodit-form__group .jodit-input_group > input:not([class*=col-]) { + width: 100% + } + + .jodit-dialog__content .jodit-form__group .jodit-input_group-buttons { + font-size: 0; + vertical-align: middle; + white-space: nowrap; + width: 1% + } + + .jodit-dialog__content .jodit-form__group .jodit-input_group-buttons > .jodit-button { + border: 1px solid var(--jd-color-border); + border-radius: 0; + height: 34px; + line-height: 34px; + margin-left: -1px + } + +.jodit-dialog__footer { + display: none; + flex-wrap: nowrap; + justify-content: space-between; + padding: var(--jd-padding-default) +} + + .jodit-dialog__footer button { + margin-right: calc(var(--jd-padding-default)/2) + } + + .jodit-dialog__footer button:last-child { + margin-right: 0 + } + +.jodit-dialog__column { + display: flex +} + +.jodit-dialog__resizer { + display: none; + position: relative +} + + .jodit-dialog__resizer svg { + bottom: 0; + cursor: nwse-resize; + height: 12px; + overflow: hidden; + position: absolute; + right: 0; + width: 12px; + fill: var(--jd-color-gray-dark); + user-select: none + } + +.jodit-dialog_resizable_true .jodit-dialog__resizer { + display: block +} + +@media (max-width:480px) { + .jodit-dialog__resizer { + display: none + } +} + +.jodit-dialog_prompt { + max-width: 300px; + min-width: 200px; + padding: var(--jd-padding-default); + word-break: break-all +} + + .jodit-dialog_prompt label { + display: block; + margin-bottom: calc(var(--jd-padding-default)/2) + } + +.jodit-dialog_alert { + max-width: 300px; + min-width: 200px; + padding: var(--jd-padding-default); + word-break: break-all +} + +.jodit-dialog_footer_true .jodit-dialog__footer { + display: flex +} + +.jodit_fullsize .jodit-dialog__panel { + height: 100% !important; + inset: 0 !important; + width: 100% !important +} + + .jodit_fullsize .jodit-dialog__panel .jodit-dialog__resizer { + display: none + } + +.jodit-dialog .jodit-ui-messages { + z-index: var(--jd-z-index-dialog) +} + +:root { + --jd-image-editor-resizer-border-color: #05ff00; + --jd-image-editor-resizer-target-size: padding-default; + --jd-image-editor-resizer-target-border-color: #383838; + --jd-image-editor-resizer-target-bg-color: #8c7878 +} + +.jodit-image-editor { + height: 100%; + overflow: hidden; + padding: var(--jd-padding-default); + width: 100% +} + +@media (max-width:768px) { + .jodit-image-editor { + height: auto + } +} + +.jodit-image-editor > div, .jodit-image-editor > div > div { + height: 100% +} + +@media (max-width:768px) { + .jodit-image-editor > div, .jodit-image-editor > div > div { + height: auto; + min-height: 200px + } +} + +.jodit-image-editor * { + box-sizing: border-box +} + +.jodit-image-editor .jodit-image-editor__slider-title { + background-color: #f9f9f9; + border-bottom: 1px solid hsla(0,0%,62%,.31); + color: #333; + cursor: pointer; + font-weight: 700; + line-height: 1em; + padding: .8em 1em; + text-overflow: ellipsis; + text-shadow: #f3f3f3 0 1px 0; + user-select: none; + white-space: nowrap +} + + .jodit-image-editor .jodit-image-editor__slider-title svg { + display: inline-block; + margin-right: var(--jd-padding-default); + vertical-align: middle; + width: 16px + } + +.jodit-image-editor .jodit-image-editor__slider-content { + display: none +} + +.jodit-image-editor .jodit-image-editor__slider.jodit-image-editor_active .jodit-image-editor__slider-title { + background-color: #5d5d5d; + color: #fff; + text-shadow: #000 0 1px 0 +} + + .jodit-image-editor .jodit-image-editor__slider.jodit-image-editor_active .jodit-image-editor__slider-title svg { + fill: #fff + } + +.jodit-image-editor .jodit-image-editor__slider.jodit-image-editor_active .jodit-image-editor__slider-content { + display: block +} + +.jodit-image-editor__area { + background-color: #eee; + background-image: linear-gradient(45deg,var(--jd-color-border) 25%,transparent 25%,transparent 75%,var(--jd-color-border) 75%,var(--jd-color-border)),linear-gradient(45deg,var(--jd-color-border) 25%,transparent 25%,transparent 75%,var(--jd-color-border) 75%,var(--jd-color-border)); + background-position: 0 0,15px 15px; + background-size: 30px 30px; + display: none; + height: 100%; + overflow: hidden; + position: relative; + user-select: none; + width: 100% +} + + .jodit-image-editor__area.jodit-image-editor_active { + display: block + } + + .jodit-image-editor__area .jodit-image-editor__box { + height: 100%; + overflow: hidden; + pointer-events: none; + position: relative; + z-index: 1 + } + + .jodit-image-editor__area .jodit-image-editor__box img { + max-height: 100%; + max-width: 100%; + user-select: none + } + + .jodit-image-editor__area .jodit-image-editor__croper, .jodit-image-editor__area .jodit-image-editor__resizer { + background-repeat: no-repeat; + border: 1px solid #fff; + box-shadow: 0 0 11px #000; + height: 100px; + left: 20px; + pointer-events: none; + position: absolute; + top: var(--jd-padding-default); + width: 100px; + z-index: 2 + } + + .jodit-image-editor__area .jodit-image-editor__croper i.jodit_bottomright, .jodit-image-editor__area .jodit-image-editor__resizer i.jodit_bottomright { + background-color: var(--jd-image-editor-resizer-target-bg-color); + border: 1px solid var(--jd-image-editor-resizer-target-border-color); + border-radius: 50%; + bottom: calc(var(--jd-padding-default)*-1); + box-shadow: 0 0 11px #000; + cursor: se-resize; + display: inline-block; + height: 20px; + pointer-events: all; + position: absolute; + right: calc(var(--jd-padding-default)*-1); + width: 20px; + z-index: 4 + } + + .jodit-image-editor__area .jodit-image-editor__croper i.jodit_bottomright:active, .jodit-image-editor__area .jodit-image-editor__resizer i.jodit_bottomright:active { + border: 1px solid #ff0 + } + + .jodit-image-editor__area.jodit-image-editor__area_crop { + background: #eee; + height: 100%; + line-height: 100%; + position: relative; + text-align: center + } + + .jodit-image-editor__area.jodit-image-editor__area_crop .jodit-image-editor__box { + height: 100%; + line-height: 100%; + overflow: visible; + pointer-events: all; + text-align: left + } + + .jodit-image-editor__area.jodit-image-editor__area_crop .jodit-image-editor__box img { + height: 100%; + max-height: 100%; + max-width: 100%; + width: 100% + } + + .jodit-image-editor__area.jodit-image-editor__area_crop .jodit-image-editor__box:after { + background: hsla(0,0%,100%,.3); + content: ""; + inset: 0; + margin: auto; + position: absolute; + z-index: 1 + } + + .jodit-image-editor__area.jodit-image-editor__area_crop .jodit-image-editor__box .jodit-image-editor__croper { + cursor: move; + pointer-events: all + } + + .jodit-image-editor__area.jodit-image-editor__area_crop .jodit-image-editor__box .jodit-image-editor__croper i.jodit-image-editor__sizes { + background: rgba(0,0,0,.2); + border-radius: .4em; + bottom: -30px; + color: #fff; + display: block; + font-size: 12px; + left: 100%; + padding: 9px 6px; + position: absolute; + text-align: center; + text-shadow: none; + white-space: pre + } + + .jodit-image-editor__area.jodit-image-editor__area_crop.jodit-image-editor_active { + align-items: center; + display: flex; + justify-content: center + } + +.jodit-file-browser-files { + display: none; + height: 100%; + overflow-anchor: auto; + position: relative; + vertical-align: top +} + + .jodit-file-browser-files .jodit-button { + border-radius: 0 + } + +.jodit-file-browser-files_loading_true:before { + content: ""; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100% +} + +.jodit-file-browser-files_loading_true:after { + animation: b 2s ease-out 0s infinite; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAABRsSURBVHja7F1/aJfVGn/33RgUg8FiNfK2WCykyS7GLoYyUbwYipZMumgLo+iPS9HlXhSHkRXdislESxMz0mapuaFo2myjkfnNlTQ2FJdTu8NvLVcrdbpcfGvxrfs823m/vXt3fjznvOedzr0PPJzzPe+7d+97Ps95nuc851fGAw884CD98ccfI1Jqmc3UpEyQz4FkMqRTgYshn8fymZ57SyGbzf5mENIOz9+ngE9Atg/SLkhPQHoWeEDn3SmpSZlJnvf7ypUrTpb7IyMjY+gGN6WWmaY84l2T3c+u58D1csjOgvwsyBdBvsDRo2zgMl/ZNM59vcAJ4Dj8nzikLa5QmBLv28YCfPd3li7gPHBMwKdcEwhCJgN6FoLOWJtUgiWovALG04FXsbI44xbgw8AplbaU/Q+ZQNgGf0gA/JWhC1aQyle1eN91rPRKKKuEsjzZvSph0m2RiutpIYRrfZC8B+l7kB6jgq0CnQIy9X39v2NYQW5FeUFQlQVN/aALyiYBPw/5M5B+Dvw02vMggqcDukEl57F3xHf9H747+4bA5oD6dzqaYEgAqIDbBl9RhvZ4H/B5yL+IDp3oXhmwNkm3lTLn80VIz+O3QFqm2/rHwgeI6QDOa006LZ3Q4lHNNwK3AVeYAD4WgmHQUivYNzWyb7xufICYaavXVbuKZ6MXfwRVJ+TnXW+Am/oMnNaO3/Y5pPitcyh/a6LqtXwAt+J01LVFEzAJ0jpIj7JunJYd1wHchnBQHUSC3Uan8WPgPVgHlBiBCcAkH4Da2i2DjwGZlcy5W0K17zLwVb9NgaY4iJpawJs+BCnWwUo3SKXT4oOAP8IHCFsIfMCguj8JaQ2kOaaA227d10ALuIR1gHVxErjctPtHBd8btSR3A4MIgSePAZxqVPeQlthq7ZRuZVABCVkLuGkJpGgKsY4ybfUEVO84qhsoAzSgrUfHZ1UQVe99B6o2oMYdwg7latAq5iROGoueQExW6UE0gCe/ANIh9SZ6jqkWsN3STZ0rHWEgpkNmEvILxqQbSAXaAPxqSBswQkbpbpo6fGPR0m3GBYjBIIwqNjCTEAr4wkBQUA0AjKNrdZCu0okAqgQhTKCDhFxV91BNgsDuYx3WQZptG3xtDUCJEDKvthGuLVEJlq4gUMyAylfQERadPrhKOHTmB3Ces4RFEXNsgW8UClbZcEhxqPQIpHOord2k1ZsAH4YvYNJXN3EgWX4Ocw4LbIEvDQSJfADJtULWxSuj+BBUP4DaC6D0DkyFg6JKTVo/5brvXqzbo2zSi3af3/9bGgrW1Ar5kH4MXEzVHEHVf5CuYZC4fti9AoI/gXX8Eda5Tp9f9I4xWWsnOoc5zNMv1okjmKp/vzay3epNJ4+YmALdoWBPWTHksc5zTU1AekqYt7LcWTruTYTZQdmQHoB0GuXv/de8L8e7xrsuA8kPNtx3AZIOxp3APc7wvD6kvi+//DLh3nvPPfegWs1jf4dBGGxpOA+hlOXzgw7VBjEBnDKcs4jzDOZDOmjqD2SJQFGBx9JaSOcQ7xVO2RIJhf86AfB+Z3huHs7Ra2pra+ugtubTp0+jMLgC0e6/ftddd6EgzMO5iGwSaq4NITCdLczy6GzXAj8KnDIxAaM0AKeViwCtgbRSNgGUJwQyDaACngO4w6S/CXgb8KEvvvgiFUaw59y5c64mWXvnnXdmsijdYxjpdP6cXh6oS0g1Bb48zpFEzValA3663pcuXaoleSzFltBIlWhRmWx+v6yMcQJ4PU7A/Oyzz/qca0R33HEHrjlAEJa73rns24JqA0keTUGTjglIJpNOxsMPP6wLfiGkx53hxRbcewwXc1BAx0u4gGMNcP2nn36acq4juv322ytZ5K7UlhBo5LER3AvcTXU60wKgYbsyWTCi3LTV6wLvKesGrvrkk0/qneucCgoKHoJkHbxvYRAhMMij/zMbVzZRTMAvv/wycj4AoRv4Mk7oII4HkLp+vC6drwxt/FrgKeMBfKTe3t69UMFTgPG9B3WcQdMeBsvjhJJqnYGqjMrKSmr/tZxNWAi87o9i+1l5O6SPNjc3dzrjlPLz83HyC/aWpqk0gWZUUHZtJvxuUZmAtAYgtHycr/a6qIXz2DQI5OH1UDRjPIOPdOHChU6o+JmQXW+68JYS4vUB/bozvN5RGAImdwPZA3AC51RKrMAfyBHFGCRBnz4oe7ypqemgc4PQxYsX0YytuOWWW3BRaa3DWd0U1A/w/Z4KvBx4jcoExAitE6dzPStr3RR/QKQ5fOUJ4PsaGxtvGPC9dOnSJfyu+7ALa9MJFPx+lkU05YNBBDVdg0uwKc4eAWCZ83cC8jM+/PDDLucGpr6+Pvy+GWz/ASs9AMFvd7ax1ATEFOBjmLdSBraN3gBwHHhmQ0NDrzMB6PLly73MUYubOs3EiB/GJebyTEB6QogCnGrV6KAFR7AVeP4HH3ww4EwgunLlCn7vfACi1UQDqMb5PWUvm5qAB3HESXNomKz2GaOHv/DAgQNJZwJSf38/fvdC3J5G1iPQnf3jK5sGvx80MQHP69hxHWZ/2wN8//vvv3/BmcD0008/XWCaoEcUJ6C0eoUWeFbXBOBCzTKKJ2/YExgEXrRv374eJyLn6tWrWA+LAJRBy+o/rQUQUx0TsFwzRKzLK/bu3dseQf8nDQwMYH2sCOL0ibx9Vr6cagIKmf0nxe8pguC7vn/Pnj2bIshH088//4z1st+m+veUI6ZFFBOwLGj/XqIh0O4/HkEtJgDmcZ4/EED9e69VKk0ACoDN1u/jqrq6uv4IZjElk0msnypbwPs0wTKVCUBnYbLuMC5REA7v3r37vQhikhBgPTWrTAEFeB9NZt3C0SbAr/6DdPM4jF7/PyNotUzBU26vgAo8x+7zri3jmgAgnOJdKYrVB9QEb+zcubMrgpVOv/76K9bXGzrACwTJfw1D+9k8EzAXOE8GviEPAK+JIDXSAlhvA7yWTWztvMfiXM65PBNQrgLfUBi2v/vuu70RnPo0ODjYC0BtN3D2VNfLR5gAz04eRn17yb0p4A0RlIEI6y+la/MV1xf4fYACSEtDiP031dbWRrY/AP32229dAGCTrs1XrHHEaesFXh+gXCfooyEM2yIIrdC2ADZ/1D1eM+CagHLJ5ExTxrl9hyLsrDiDWI99EjApgPvLRwhAmQh4HV/Axwe3bt06GMEXnFKpFK4tOBgQcH95WdoEAE01nc8Xi8VEArA3gs4q7VWpfsHaCpEg4GrnoeXhOEKUw3u4yZYqbGo4Lk2KR5hZpcOsXjO9GIm0AYFycTErmoDJVLWu0Tto3bJly0CEmT36/fffkzh/UKfVE3yLkix3Xx+v5FjYaaslgiwUZxDrdbrm38guF6EAFFKAF5kEwcFPrRFcoVCrIdAiKsSlYUWqFi/zBwTXOiKsQqGOIKe1cQRmSAPkmYIv0ADY9Yuif+GYgC5Wv9kB1L6X8lAA8k3BFwhB94YNG1IRXPYJutwpINwBpNjSI/O5AhDQGUxEUIVKCRMBEGiFIQG4yX+Daf+fPacvwihUM2Czfm/KcgMLtjZZhudEY//hks2VVJlZ7tJvi5SMMApVA9gMsOVkXYvDFiO6fggFACUqJ6qKcaMBbD5uAH2AlE0fIKJxRSnUAGizcykePtWzjOo1VA2gpa0V2CVRALBbURDwQV4qiGAKVQDyLZ571JfFum0lFqTJvScvgilUytPxAxSY9boawMbD3OtFEUahaoAinQap0gA4JSzhPswSFz733HOZEVT2KZlMYr0WesGV7KpOoQRqgG6DVi4rx5EqjFWfjSCz3vqLHd9IoGyYnoBjNwpAwhBoWXlpJAChCECpv66p5ycJBCSBcwI7daZ7E83FtAiuUGgaT/WLACaYhk4MBCVk0UDKWb2c3+URVqFogOm8OqccqMW5d+Dmm29OuGsDOyw7gmUvvfRSFBCySFevXsX6LBO1cIoG8NEQ5u7KoFbLi0Kz3fODI7JGeHbwTSJADcxCq1cAWnR39yYIQUWEmVX1X2G6SYTgnhavABwL0uoF91dUV1dnR9AFp/7+fjysq0IGvIEGODYkAOwa7t/XYXl3kDzgBRF8Vgg3eczT2SqGYP97vBoA83ELrd6/WPSJCDsr6v8Jw91BRdfS6za9ewQ1qVo9RQv47plXU1NTHEFoTpcvX8aTwueJgKdoAI4wpE8Y9e4SdtgdGLK4S1gm8L8jGAO1fqy/TNmiUE1hQIwPj9AADOQk7ugRdJ9ADj+2bt26aI6AAV26dAnr7THqnsFEYTgEnBRtFl0fwk6hOcCrIjiNaBXOAKIcuq3hG4w4fTXma+lNOEHEZFs4hcA8+eqrr0a+gAZdvHgRbf+TsrMDDMxBr2v/eT7A0L5+8HN7AKdPFhncHMGqZftfB84Wga0yBwKtsN1hk4B5PsCIrd0C2HwRz924cWNlBK2afvzxx0rX89c5Qo4gCNv85bwDI7r8XUKqynfL/KmHazZt2pQbQSymH374AffuqeEB7gWXCrzHFCCmXf5niE4NWxPkJFAJ41GmtRHMUtWP9TNJdYScgQZYo3NoFEYF21WmgAq8776KzZs3Px1BPZq+//57rJcKXhg3oClo90b/qCeHvqLjA2j6B+u2bNlSFkH+J3333XdlAMo6ntq3cJroK6K4gOzgyP2oBaj2nqIdPGXYKzjw5ptvToqgd5yenh5U+Qcgmy07UdxQA7QD7xfFClSnh68Oelag6H5n+Fj6j9566638iQz++fPn8wGMRq/dV4EviwVwrq0W9QpUJsAdINof5LRQxfNLgBu2bt06IaePffvttzjDp8EZ3r6dDL7sQEkfyAdVW82rjo9H/hdkB2y2ft89eEB149tvvz2hlqh/8803OazlTzMFX6ENcKLvU7LgEMUEuIc9vqLb+inBJE8ezyo+un379gkxaPT111/jdx4FEGbJwOd1A2VdQ9896Pj1qIJDMSJI6yHpNGnpGlHFqVgp77zzzg29tjCRSBQx8KfKWrmJBvDkO4HXU3oI7pQwFUDpc/8s9ABk14uB23bs2HFDTiU7d+7cAqj4NrbESxtojeAQYjWoOnyaqwF4AsFSnDm81lT1y2YZ+cpwLmHDzp07a3bt2nVDTCrt6urKBq5hDl8eBXCTHgGjtWxTaVK8IEYFjKWrvVPIdU8VE2kMgUCsBD6ye/fukvEM/ldffVUCFX4EsitVtl3UYjU0wDHg1dQIodQJFJShKXgE0j5dLaACn6MJkKcDH6+rq6uur68fV72EM2fO5Jw9e7YasseBp5u0cKoQsDxO9Vrqqn6R2hdGAjWEoBvSR03B9wPNA95HGDVcBXxqz549D40H8E+fPo3vecoZntGTreqzmwgBRyDw2Plu3TBxxmuvvcYFUQYwy+OQ5UoV6DITQzEJnGsdbLSyfvHixdfVptSnTp2qZMJaqtsVVtWbAiP0zap498ryt956q5OxYcMGyj/gpbhbxS5IlwSJBQQYYsZVzWtREBYtWnTN9ic+efIkOq1LmM9SZDKplioQgrJ6ZpZTVODd32kBIEoZL0UvvdFdCBoUfGo8gXM0/UHgHTireeHChaFrhePHj+N0dzxqdxnwg2xwS0vD6YIvwAOnd89nvhkZeJduu+02J2Pjxo0UKZO9GM7w+cjdFMIgCmiqAXj39bO5DPFYLNY8b948ayeXtLW1lbIT1mcxzjVZUGtqCjh44Bj/34H7ZXjJhCItAAHAd1Mc0fvcPYAqCPhBhIHDF5jP0MF2QkmwE02HTMjs2bPTpqOlpSXPVeHABSwoVcLsOebzTWZH2fADOClO7ZqB3yfDTWUSUACyiHZG9UJY0SiNH7PKIjsiqt6BooegIhTMOYxHUTweN3q26EAN/wkr3t+qvEaKczbvxzoXPcf7brL/a9oNFKXYPZzpnUpGlX6dbqHIDIRNlIWXsuibbjdQkGLdzoQ0YfJ/uJFAamsndllw19HZzDlxVGFmkcqilFnSEFotnnKNOlZPGQX0lWOdzoa01xR47nCwDtBEpwbHoedj94wy0KSKCOoIQhgaQrXZgkoYdMCXPAvrcr57WITuXEHlcLCu00cQGjza7BEcRjbRAFSNQAXXVAh0zuY1BV/Q2r3pekixnz+oGRomvVtMV9Vr3I/98RXAC73LzoM4grIWb1sIxgp8iSnAOlsIKdZhynB8QG8wiKIBDPyCQ5C9F0cRKY6gDFwZ2DaFIEzwCS3e3b/nXlzKras1dFr/KA2go/5FLVRwfzdzDtfodgupZoFqGohbqIYGPsH+Yx3NxF6V7D2omkXlmMZM1T8PDMXfoUl4BruKkHaaaANbtj2MnoEJ+L6/72RdvGe8Kt9kjqBOj4SsAUyvce7BCSV/Ba6C/EBYXcSg5oIKtqkj5ikbgLSKqfwWaheRWqZ6j1gIAFPuQW2AI3lTIN0b1CSonMSwYgCU6wqQ8NunsOHcQcozVKZIVwhiKjVuMEihY0YwevgPSDG0eUy3ezjWYOsEhRRAHWPf/A93Egc1MKTj+FGEIGZhIEgJiMzPYPlmHNxgjmLTtRSCsOw+o2YWzcNvbTYIBVsVgrQGsAW+6cCSJx9nUcS/QbrfVAjCDgQZ/P1+yOM33Q9pPMizqCaAKgSxsMCntk6B2sdVyYsh/QvwC7hriY4QhCkUGi0e3/kF/AYow29pJ8YArJkAihDEwgRfVyNw8rif7X+B74Y8qs03nOGNDq0IgQ3Afff0sXecAfm72bv3UFoxpdWbtH7V32cFcfgoLcyCEKQdJ9zVHNL/AM9ijOP808MYD/CP7UvuO8ZGP+OMB3nP4T1PNfYvey/KXAPKd2XpevA27iWYANk9g8yZamblOa5A4FQtZ/jEsjybWsBTaX1sQkbcA/iACAQd0E2EQgU8RUiyKC02qGnQjS6qwPP9LQJwiLFLuUwQcBuaIiYQuBjTPc8wk/32VtYJFq104xQnmLlJMPuNNr3fUEuQQtDUVm8DeNcc/F+AAQBKd8HaIWdjwQAAAABJRU5ErkJggg==) no-repeat 50%; + background-size: 100% 100%; + content: ""; + display: inline-block; + height: var(--jd-icon-loader-size); + left: 50%; + margin-left: calc(var(--jd-icon-loader-size)/-2); + margin-top: calc(var(--jd-icon-loader-size)/-2); + opacity: .7; + position: absolute; + top: 50%; + vertical-align: middle; + width: var(--jd-icon-loader-size); + will-change: transform +} + +.jodit-file-browser-files::-webkit-scrollbar { + width: calc(var(--jd-padding-default)/2) +} + +.jodit-file-browser-files::-webkit-scrollbar-track { + box-shadow: inset 0 0 6px rgba(0,0,0,.3) +} + +.jodit-file-browser-files::-webkit-scrollbar-thumb { + background-color: #a9a9a9; + outline: 1px solid #708090 +} + +.jodit-file-browser-files_active_true { + align-content: flex-start; + display: flex; + flex-wrap: wrap; + overflow-y: auto; + padding: calc(var(--jd-padding-default)/2); + width: 100% +} + +.jodit-file-browser-files__item { + align-items: center; + border: 1px solid var(--jd-color-border); + display: flex; + font-size: 0; + height: var(--jd-col-size); + justify-content: center; + margin: calc(var(--jd-padding-default)/2); + overflow: hidden; + position: relative; + text-align: center; + transition: border .1s linear,bottom .1s linear; + width: var(--jd-col-size) +} + +@media (max-width:480px) { + .jodit-file-browser-files__item { + width: calc(50% - var(--jd-padding-default)) + } +} + +.jodit-file-browser-files__item img { + max-width: 100% +} + +.jodit-file-browser-files__item:hover { + border-color: #433b5c +} + +.jodit-file-browser-files__item_active_true { + background-color: var(--jd-color-border-active); + border-color: var(--jd-color-border-selected) +} + + .jodit-file-browser-files__item_active_true .jodit-file-browser-files__item-info { + background-color: var(--jd-color-border-active); + color: #fff; + text-shadow: none + } + +.jodit-file-browser-files__item-info { + background-color: var(--jd-info-background); + bottom: 0; + color: #333; + font-size: 14px; + left: 0; + line-height: 16px; + opacity: .85; + overflow: visible; + padding: .3em .6em; + position: absolute; + right: 0; + text-align: left; + text-shadow: #eee 0 1px 0; + transition: opacity .4s ease; + white-space: normal +} + + .jodit-file-browser-files__item-info > span { + display: block; + font-size: .75em; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap + } + + .jodit-file-browser-files__item-info > span.jodit-file-browser-files__item-info-filename { + font-size: .9em; + font-weight: 700 + } + +.jodit-file-browser-files__item:hover:not(.jodit-file-browser-files__item_active_true) .jodit-file-browser-files__item-info { + bottom: -100px +} + +.jodit-file-browser-files_view_list { + scroll-behavior: smooth +} + + .jodit-file-browser-files_view_list a { + border-width: 0 0 1px; + display: block; + height: 26px; + line-height: 26px; + margin: 0; + text-align: left; + white-space: nowrap; + width: 100% + } + + .jodit-file-browser-files_view_list a img { + display: inline-block; + margin-left: 4px; + max-width: 16px; + min-width: 16px; + vertical-align: middle + } + + .jodit-file-browser-files_view_list a .jodit-file-browser-files__item-info { + background-color: transparent; + display: inline-block; + font-size: 0; + height: 100%; + line-height: inherit; + margin-left: 4px; + padding: 0; + position: static; + vertical-align: middle; + width: calc(100% - 20px) + } + + .jodit-file-browser-files_view_list a .jodit-file-browser-files__item-info > span { + display: inline-block; + font-size: 12px; + height: 100% + } + + .jodit-file-browser-files_view_list a .jodit-file-browser-files__item-info-filename { + width: 50% + } + + .jodit-file-browser-files_view_list a .jodit-file-browser-files__item-info-filechanged, .jodit-file-browser-files_view_list a .jodit-file-browser-files__item-info-filesize { + width: 25% + } + + .jodit-file-browser-files_view_list a:hover { + background-color: #433b5c + } + + .jodit-file-browser-files_view_list a:hover .jodit-file-browser-files__item-info { + color: #fff; + text-shadow: none + } + + .jodit-file-browser-files_view_list a:before { + content: ""; + display: inline-block; + height: 100%; + vertical-align: middle + } + +:root { + --jd-color-folder-title: #b1b1b1 +} + +.jodit-file-browser-tree { + --jd-color-background-filebrowser-folders: #3f3f3f; + display: none; + height: 100%; + overflow-anchor: auto; + position: relative; + vertical-align: top +} + + .jodit-file-browser-tree .jodit-button { + border-radius: 0 + } + +.jodit-file-browser-tree_loading_true:before { + content: ""; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100% +} + +.jodit-file-browser-tree_loading_true:after { + animation: b 2s ease-out 0s infinite; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAABRsSURBVHja7F1/aJfVGn/33RgUg8FiNfK2WCykyS7GLoYyUbwYipZMumgLo+iPS9HlXhSHkRXdislESxMz0mapuaFo2myjkfnNlTQ2FJdTu8NvLVcrdbpcfGvxrfs823m/vXt3fjznvOedzr0PPJzzPe+7d+97Ps95nuc851fGAw884CD98ccfI1Jqmc3UpEyQz4FkMqRTgYshn8fymZ57SyGbzf5mENIOz9+ngE9Atg/SLkhPQHoWeEDn3SmpSZlJnvf7ypUrTpb7IyMjY+gGN6WWmaY84l2T3c+u58D1csjOgvwsyBdBvsDRo2zgMl/ZNM59vcAJ4Dj8nzikLa5QmBLv28YCfPd3li7gPHBMwKdcEwhCJgN6FoLOWJtUgiWovALG04FXsbI44xbgw8AplbaU/Q+ZQNgGf0gA/JWhC1aQyle1eN91rPRKKKuEsjzZvSph0m2RiutpIYRrfZC8B+l7kB6jgq0CnQIy9X39v2NYQW5FeUFQlQVN/aALyiYBPw/5M5B+Dvw02vMggqcDukEl57F3xHf9H747+4bA5oD6dzqaYEgAqIDbBl9RhvZ4H/B5yL+IDp3oXhmwNkm3lTLn80VIz+O3QFqm2/rHwgeI6QDOa006LZ3Q4lHNNwK3AVeYAD4WgmHQUivYNzWyb7xufICYaavXVbuKZ6MXfwRVJ+TnXW+Am/oMnNaO3/Y5pPitcyh/a6LqtXwAt+J01LVFEzAJ0jpIj7JunJYd1wHchnBQHUSC3Uan8WPgPVgHlBiBCcAkH4Da2i2DjwGZlcy5W0K17zLwVb9NgaY4iJpawJs+BCnWwUo3SKXT4oOAP8IHCFsIfMCguj8JaQ2kOaaA227d10ALuIR1gHVxErjctPtHBd8btSR3A4MIgSePAZxqVPeQlthq7ZRuZVABCVkLuGkJpGgKsY4ybfUEVO84qhsoAzSgrUfHZ1UQVe99B6o2oMYdwg7latAq5iROGoueQExW6UE0gCe/ANIh9SZ6jqkWsN3STZ0rHWEgpkNmEvILxqQbSAXaAPxqSBswQkbpbpo6fGPR0m3GBYjBIIwqNjCTEAr4wkBQUA0AjKNrdZCu0okAqgQhTKCDhFxV91BNgsDuYx3WQZptG3xtDUCJEDKvthGuLVEJlq4gUMyAylfQERadPrhKOHTmB3Ces4RFEXNsgW8UClbZcEhxqPQIpHOord2k1ZsAH4YvYNJXN3EgWX4Ocw4LbIEvDQSJfADJtULWxSuj+BBUP4DaC6D0DkyFg6JKTVo/5brvXqzbo2zSi3af3/9bGgrW1Ar5kH4MXEzVHEHVf5CuYZC4fti9AoI/gXX8Eda5Tp9f9I4xWWsnOoc5zNMv1okjmKp/vzay3epNJ4+YmALdoWBPWTHksc5zTU1AekqYt7LcWTruTYTZQdmQHoB0GuXv/de8L8e7xrsuA8kPNtx3AZIOxp3APc7wvD6kvi+//DLh3nvPPfegWs1jf4dBGGxpOA+hlOXzgw7VBjEBnDKcs4jzDOZDOmjqD2SJQFGBx9JaSOcQ7xVO2RIJhf86AfB+Z3huHs7Ra2pra+ugtubTp0+jMLgC0e6/ftddd6EgzMO5iGwSaq4NITCdLczy6GzXAj8KnDIxAaM0AKeViwCtgbRSNgGUJwQyDaACngO4w6S/CXgb8KEvvvgiFUaw59y5c64mWXvnnXdmsijdYxjpdP6cXh6oS0g1Bb48zpFEzValA3663pcuXaoleSzFltBIlWhRmWx+v6yMcQJ4PU7A/Oyzz/qca0R33HEHrjlAEJa73rns24JqA0keTUGTjglIJpNOxsMPP6wLfiGkx53hxRbcewwXc1BAx0u4gGMNcP2nn36acq4juv322ytZ5K7UlhBo5LER3AvcTXU60wKgYbsyWTCi3LTV6wLvKesGrvrkk0/qneucCgoKHoJkHbxvYRAhMMij/zMbVzZRTMAvv/wycj4AoRv4Mk7oII4HkLp+vC6drwxt/FrgKeMBfKTe3t69UMFTgPG9B3WcQdMeBsvjhJJqnYGqjMrKSmr/tZxNWAi87o9i+1l5O6SPNjc3dzrjlPLz83HyC/aWpqk0gWZUUHZtJvxuUZmAtAYgtHycr/a6qIXz2DQI5OH1UDRjPIOPdOHChU6o+JmQXW+68JYS4vUB/bozvN5RGAImdwPZA3AC51RKrMAfyBHFGCRBnz4oe7ypqemgc4PQxYsX0YytuOWWW3BRaa3DWd0U1A/w/Z4KvBx4jcoExAitE6dzPStr3RR/QKQ5fOUJ4PsaGxtvGPC9dOnSJfyu+7ALa9MJFPx+lkU05YNBBDVdg0uwKc4eAWCZ83cC8jM+/PDDLucGpr6+Pvy+GWz/ASs9AMFvd7ax1ATEFOBjmLdSBraN3gBwHHhmQ0NDrzMB6PLly73MUYubOs3EiB/GJebyTEB6QogCnGrV6KAFR7AVeP4HH3ww4EwgunLlCn7vfACi1UQDqMb5PWUvm5qAB3HESXNomKz2GaOHv/DAgQNJZwJSf38/fvdC3J5G1iPQnf3jK5sGvx80MQHP69hxHWZ/2wN8//vvv3/BmcD0008/XWCaoEcUJ6C0eoUWeFbXBOBCzTKKJ2/YExgEXrRv374eJyLn6tWrWA+LAJRBy+o/rQUQUx0TsFwzRKzLK/bu3dseQf8nDQwMYH2sCOL0ibx9Vr6cagIKmf0nxe8pguC7vn/Pnj2bIshH088//4z1st+m+veUI6ZFFBOwLGj/XqIh0O4/HkEtJgDmcZ4/EED9e69VKk0ACoDN1u/jqrq6uv4IZjElk0msnypbwPs0wTKVCUBnYbLuMC5REA7v3r37vQhikhBgPTWrTAEFeB9NZt3C0SbAr/6DdPM4jF7/PyNotUzBU26vgAo8x+7zri3jmgAgnOJdKYrVB9QEb+zcubMrgpVOv/76K9bXGzrACwTJfw1D+9k8EzAXOE8GviEPAK+JIDXSAlhvA7yWTWztvMfiXM65PBNQrgLfUBi2v/vuu70RnPo0ODjYC0BtN3D2VNfLR5gAz04eRn17yb0p4A0RlIEI6y+la/MV1xf4fYACSEtDiP031dbWRrY/AP32229dAGCTrs1XrHHEaesFXh+gXCfooyEM2yIIrdC2ADZ/1D1eM+CagHLJ5ExTxrl9hyLsrDiDWI99EjApgPvLRwhAmQh4HV/Axwe3bt06GMEXnFKpFK4tOBgQcH95WdoEAE01nc8Xi8VEArA3gs4q7VWpfsHaCpEg4GrnoeXhOEKUw3u4yZYqbGo4Lk2KR5hZpcOsXjO9GIm0AYFycTErmoDJVLWu0Tto3bJly0CEmT36/fffkzh/UKfVE3yLkix3Xx+v5FjYaaslgiwUZxDrdbrm38guF6EAFFKAF5kEwcFPrRFcoVCrIdAiKsSlYUWqFi/zBwTXOiKsQqGOIKe1cQRmSAPkmYIv0ADY9Yuif+GYgC5Wv9kB1L6X8lAA8k3BFwhB94YNG1IRXPYJutwpINwBpNjSI/O5AhDQGUxEUIVKCRMBEGiFIQG4yX+Daf+fPacvwihUM2Czfm/KcgMLtjZZhudEY//hks2VVJlZ7tJvi5SMMApVA9gMsOVkXYvDFiO6fggFACUqJ6qKcaMBbD5uAH2AlE0fIKJxRSnUAGizcykePtWzjOo1VA2gpa0V2CVRALBbURDwQV4qiGAKVQDyLZ571JfFum0lFqTJvScvgilUytPxAxSY9boawMbD3OtFEUahaoAinQap0gA4JSzhPswSFz733HOZEVT2KZlMYr0WesGV7KpOoQRqgG6DVi4rx5EqjFWfjSCz3vqLHd9IoGyYnoBjNwpAwhBoWXlpJAChCECpv66p5ycJBCSBcwI7daZ7E83FtAiuUGgaT/WLACaYhk4MBCVk0UDKWb2c3+URVqFogOm8OqccqMW5d+Dmm29OuGsDOyw7gmUvvfRSFBCySFevXsX6LBO1cIoG8NEQ5u7KoFbLi0Kz3fODI7JGeHbwTSJADcxCq1cAWnR39yYIQUWEmVX1X2G6SYTgnhavABwL0uoF91dUV1dnR9AFp/7+fjysq0IGvIEGODYkAOwa7t/XYXl3kDzgBRF8Vgg3eczT2SqGYP97vBoA83ELrd6/WPSJCDsr6v8Jw91BRdfS6za9ewQ1qVo9RQv47plXU1NTHEFoTpcvX8aTwueJgKdoAI4wpE8Y9e4SdtgdGLK4S1gm8L8jGAO1fqy/TNmiUE1hQIwPj9AADOQk7ugRdJ9ADj+2bt26aI6AAV26dAnr7THqnsFEYTgEnBRtFl0fwk6hOcCrIjiNaBXOAKIcuq3hG4w4fTXma+lNOEHEZFs4hcA8+eqrr0a+gAZdvHgRbf+TsrMDDMxBr2v/eT7A0L5+8HN7AKdPFhncHMGqZftfB84Wga0yBwKtsN1hk4B5PsCIrd0C2HwRz924cWNlBK2afvzxx0rX89c5Qo4gCNv85bwDI7r8XUKqynfL/KmHazZt2pQbQSymH374AffuqeEB7gWXCrzHFCCmXf5niE4NWxPkJFAJ41GmtRHMUtWP9TNJdYScgQZYo3NoFEYF21WmgAq8776KzZs3Px1BPZq+//57rJcKXhg3oClo90b/qCeHvqLjA2j6B+u2bNlSFkH+J3333XdlAMo6ntq3cJroK6K4gOzgyP2oBaj2nqIdPGXYKzjw5ptvToqgd5yenh5U+Qcgmy07UdxQA7QD7xfFClSnh68Oelag6H5n+Fj6j9566638iQz++fPn8wGMRq/dV4EviwVwrq0W9QpUJsAdINof5LRQxfNLgBu2bt06IaePffvttzjDp8EZ3r6dDL7sQEkfyAdVW82rjo9H/hdkB2y2ft89eEB149tvvz2hlqh/8803OazlTzMFX6ENcKLvU7LgEMUEuIc9vqLb+inBJE8ezyo+un379gkxaPT111/jdx4FEGbJwOd1A2VdQ9896Pj1qIJDMSJI6yHpNGnpGlHFqVgp77zzzg29tjCRSBQx8KfKWrmJBvDkO4HXU3oI7pQwFUDpc/8s9ABk14uB23bs2HFDTiU7d+7cAqj4NrbESxtojeAQYjWoOnyaqwF4AsFSnDm81lT1y2YZ+cpwLmHDzp07a3bt2nVDTCrt6urKBq5hDl8eBXCTHgGjtWxTaVK8IEYFjKWrvVPIdU8VE2kMgUCsBD6ye/fukvEM/ldffVUCFX4EsitVtl3UYjU0wDHg1dQIodQJFJShKXgE0j5dLaACn6MJkKcDH6+rq6uur68fV72EM2fO5Jw9e7YasseBp5u0cKoQsDxO9Vrqqn6R2hdGAjWEoBvSR03B9wPNA95HGDVcBXxqz549D40H8E+fPo3vecoZntGTreqzmwgBRyDw2Plu3TBxxmuvvcYFUQYwy+OQ5UoV6DITQzEJnGsdbLSyfvHixdfVptSnTp2qZMJaqtsVVtWbAiP0zap498ryt956q5OxYcMGyj/gpbhbxS5IlwSJBQQYYsZVzWtREBYtWnTN9ic+efIkOq1LmM9SZDKplioQgrJ6ZpZTVODd32kBIEoZL0UvvdFdCBoUfGo8gXM0/UHgHTireeHChaFrhePHj+N0dzxqdxnwg2xwS0vD6YIvwAOnd89nvhkZeJduu+02J2Pjxo0UKZO9GM7w+cjdFMIgCmiqAXj39bO5DPFYLNY8b948ayeXtLW1lbIT1mcxzjVZUGtqCjh44Bj/34H7ZXjJhCItAAHAd1Mc0fvcPYAqCPhBhIHDF5jP0MF2QkmwE02HTMjs2bPTpqOlpSXPVeHABSwoVcLsOebzTWZH2fADOClO7ZqB3yfDTWUSUACyiHZG9UJY0SiNH7PKIjsiqt6BooegIhTMOYxHUTweN3q26EAN/wkr3t+qvEaKczbvxzoXPcf7brL/a9oNFKXYPZzpnUpGlX6dbqHIDIRNlIWXsuibbjdQkGLdzoQ0YfJ/uJFAamsndllw19HZzDlxVGFmkcqilFnSEFotnnKNOlZPGQX0lWOdzoa01xR47nCwDtBEpwbHoedj94wy0KSKCOoIQhgaQrXZgkoYdMCXPAvrcr57WITuXEHlcLCu00cQGjza7BEcRjbRAFSNQAXXVAh0zuY1BV/Q2r3pekixnz+oGRomvVtMV9Vr3I/98RXAC73LzoM4grIWb1sIxgp8iSnAOlsIKdZhynB8QG8wiKIBDPyCQ5C9F0cRKY6gDFwZ2DaFIEzwCS3e3b/nXlzKras1dFr/KA2go/5FLVRwfzdzDtfodgupZoFqGohbqIYGPsH+Yx3NxF6V7D2omkXlmMZM1T8PDMXfoUl4BruKkHaaaANbtj2MnoEJ+L6/72RdvGe8Kt9kjqBOj4SsAUyvce7BCSV/Ba6C/EBYXcSg5oIKtqkj5ikbgLSKqfwWaheRWqZ6j1gIAFPuQW2AI3lTIN0b1CSonMSwYgCU6wqQ8NunsOHcQcozVKZIVwhiKjVuMEihY0YwevgPSDG0eUy3ezjWYOsEhRRAHWPf/A93Egc1MKTj+FGEIGZhIEgJiMzPYPlmHNxgjmLTtRSCsOw+o2YWzcNvbTYIBVsVgrQGsAW+6cCSJx9nUcS/QbrfVAjCDgQZ/P1+yOM33Q9pPMizqCaAKgSxsMCntk6B2sdVyYsh/QvwC7hriY4QhCkUGi0e3/kF/AYow29pJ8YArJkAihDEwgRfVyNw8rif7X+B74Y8qs03nOGNDq0IgQ3Afff0sXecAfm72bv3UFoxpdWbtH7V32cFcfgoLcyCEKQdJ9zVHNL/AM9ijOP808MYD/CP7UvuO8ZGP+OMB3nP4T1PNfYvey/KXAPKd2XpevA27iWYANk9g8yZamblOa5A4FQtZ/jEsjybWsBTaX1sQkbcA/iACAQd0E2EQgU8RUiyKC02qGnQjS6qwPP9LQJwiLFLuUwQcBuaIiYQuBjTPc8wk/32VtYJFq104xQnmLlJMPuNNr3fUEuQQtDUVm8DeNcc/F+AAQBKd8HaIWdjwQAAAABJRU5ErkJggg==) no-repeat 50%; + background-size: 100% 100%; + content: ""; + display: inline-block; + height: var(--jd-icon-loader-size); + left: 50%; + margin-left: calc(var(--jd-icon-loader-size)/-2); + margin-top: calc(var(--jd-icon-loader-size)/-2); + opacity: .7; + position: absolute; + top: 50%; + vertical-align: middle; + width: var(--jd-icon-loader-size); + will-change: transform +} + +.jodit-file-browser-tree::-webkit-scrollbar { + width: calc(var(--jd-padding-default)/2) +} + +.jodit-file-browser-tree::-webkit-scrollbar-track { + box-shadow: inset 0 0 6px rgba(0,0,0,.3) +} + +.jodit-file-browser-tree::-webkit-scrollbar-thumb { + background-color: #a9a9a9; + outline: 1px solid #708090 +} + +.jodit-file-browser-tree_active_true { + background-color: var(--jd-color-background-filebrowser-folders); + display: flex; + flex-direction: column; + max-width: 290px; + min-width: 200px; + overflow-y: auto; + width: var(--jd-first-column); + z-index: 2 +} + +@media (max-width:480px) { + .jodit-file-browser-tree_active_true { + height: 100px; + max-width: 100%; + width: auto + } +} + +.jodit-file-browser-tree_active_true::-webkit-scrollbar { + width: calc(var(--jd-padding-default)/2) +} + +.jodit-file-browser-tree_active_true::-webkit-scrollbar-track { + box-shadow: inset 0 0 6px rgba(0,0,0,.3) +} + +.jodit-file-browser-tree_active_true::-webkit-scrollbar-thumb { + background-color: hsla(0,0%,50%,.5); + outline: 1px solid #708090 +} + +.jodit-file-browser-tree__item { + align-items: center; + border-bottom: 1px solid #474747; + color: var(--jd-color-folder-title); + display: flex; + justify-content: space-between; + min-height: 38px; + padding: calc(var(--jd-padding-default)/2) var(--jd-padding-default); + position: relative; + text-decoration: none; + transition: background-color .2s ease 0s; + word-break: break-all +} + +.jodit-file-browser-tree__item-title { + color: var(--jd-color-folder-title); + flex: 1 +} + +.jodit-file-browser-tree__item .jodit-icon_folder { + align-items: center; + display: flex; + height: calc(var(--jd-icon-size) + 4px); + justify-content: center; + margin-left: calc(var(--jd-padding-default)/2); + opacity: .3; + width: calc(var(--jd-icon-size) + 4px) +} + + .jodit-file-browser-tree__item .jodit-icon_folder svg { + height: var(--jd-icon-size); + width: var(--jd-icon-size); + fill: var(--jd-color-folder-title) !important; + stroke: var(--jd-color-folder-title) !important + } + + .jodit-file-browser-tree__item .jodit-icon_folder:hover { + background: #696969 + } + +.jodit-file-browser-tree__item:hover { + background-color: var(--jd-color-background-button-hover) +} + +.jodit-file-browser-tree__item:hover-title { + color: var(--jd-color-text) +} + +.jodit-file-browser-tree__item:hover i.jodit-icon_folder { + opacity: .6 +} + +.jodit-file-browser-tree__source-title { + background: #5a5a5a; + border-bottom: 1px solid #484848; + color: #969696; + display: block; + font-size: 12px; + padding: 2px 4px; + position: relative; + user-select: none; + word-break: break-all +} + +a + .jodit-file-browser-tree__source-title { + margin-top: var(--jd-padding-default) +} + +:root { + --jd-first-column: 31%; + --jd-cols: 4; + --jd-info-background: #e9e9e9; + --jd-icon-size: 12px; + --jd-col-size: 150px +} + +.jodit-file-browser { + display: flex; + font-family: var(--jd-font-default); + height: 100% +} + +.jodit-file-browser_no-files_true { + padding: var(--jd-padding-default) +} + +@media (max-width:480px) { + .jodit-file-browser { + flex-flow: column-reverse + } +} + +.jodit-dialog .jodit-dialog__header-title.jodit-file-browser__title-box { + align-items: center; + display: flex; + padding-left: var(--jd-padding-default) +} + +.jodit-file-browser-preview { + align-items: center; + display: flex; + height: 100%; + justify-content: center; + margin: auto; + max-height: 100%; + max-width: min(100%,1000px); + min-height: min(100%,500px); + min-width: 400px; + position: relative; + text-align: center +} + +@media (max-width:768px) { + .jodit-file-browser-preview { + height: 100%; + max-height: 100%; + max-width: 100%; + min-height: auto; + min-width: auto + } +} + +.jodit-file-browser-preview__box { + align-items: center; + display: flex; + flex-grow: 1; + justify-content: center +} + +.jodit-file-browser-preview__navigation { + cursor: pointer; + height: 100%; + left: 0; + position: absolute; + top: 0 +} + +.jodit-file-browser-preview__navigation_arrow_next { + left: auto; + right: 0 +} + +.jodit-file-browser-preview__navigation svg { + height: 45px; + position: relative; + top: 50%; + width: 45px; + fill: #9e9ba7; + transform: translateY(-50%); + transition: fill .3s linear +} + +.jodit-file-browser-preview__navigation:hover svg { + fill: #000 +} + +.jodit-file-browser-preview img { + max-height: 100%; + max-width: 100% +} + +.jodit-status-bar { + align-items: center; + background-color: var(--jd-color-panel); + border-radius: 0 0 var(--jd-border-radius-default) var(--jd-border-radius-default); + color: var(--jd-color-text-icons); + display: flex; + font-size: var(--jd-font-size-small); + height: 20px; + justify-content: flex-start; + overflow: hidden; + padding: 0 calc(var(--jd-padding-default)/2); + text-transform: uppercase +} + +.jodit-status-bar_resize-handle_true { + padding-right: 14px +} + +.jodit-status-bar:before { + content: ""; + flex: auto; + order: 1 +} + +.jodit-status-bar .jodit-status-bar__item { + line-height: 1.5714em; + margin: 0 var(--jd-padding-default) 0 0; + order: 0; + padding: 0 +} + + .jodit-status-bar .jodit-status-bar__item, .jodit-status-bar .jodit-status-bar__item > span { + font-family: var(--jd-font-default); + font-size: var(--jd-font-size-default); + font-size: var(--jd-font-size-small) + } + + .jodit-status-bar .jodit-status-bar__item.jodit-status-bar__item-right { + margin: 0 0 0 var(--jd-padding-default); + order: 2 + } + + .jodit-status-bar .jodit-status-bar__item a { + border-radius: 3px; + cursor: default; + text-decoration: none + } + + .jodit-status-bar .jodit-status-bar__item a:hover { + background-color: var(--jd-color-background-gray); + text-decoration: none + } + +.jodit-status-bar a.jodit-status-bar-link { + cursor: pointer +} + + .jodit-status-bar a.jodit-status-bar-link, .jodit-status-bar a.jodit-status-bar-link:hover, .jodit-status-bar a.jodit-status-bar-link:visited { + background-color: transparent; + color: var(--jd-color-text-icons) + } + + .jodit-status-bar a.jodit-status-bar-link:hover { + text-decoration: underline + } + +.jodit-workplace + .jodit-status-bar:not(:empty) { + border-top: 1px solid var(--jd-color-border) +} + +.jodit_disabled .jodit-status-bar { + opacity: .4 +} + +.jodit-drag-and-drop__file-box, .jodit_uploadfile_button { + border: 1px dashed var(--jd-color-gray); + margin: var(--jd-padding-default) 0; + overflow: hidden; + padding: 25px 0; + position: relative; + text-align: center; + width: 100% +} + + .jodit-drag-and-drop__file-box:hover, .jodit_uploadfile_button:hover { + background-color: var(--jd-color-background-button-hover) + } + + .jodit-drag-and-drop__file-box input, .jodit_uploadfile_button input { + cursor: pointer; + font-size: 400px; + inset: 0; + margin: 0; + opacity: 0; + padding: 0; + position: absolute + } + +@media (max-width:768px) { + .jodit-drag-and-drop__file-box { + max-width: 100%; + min-width: var(--jd-width-input-min); + width: auto + } +} + +:root { + --jd-anl-color-new-line: var(--jd-color-border); + --jd-anl-handle-size: 20px; + --jd-anl-handle-offset: calc(100% - var(--jd-anl-handle-size)) +} + +.jodit-add-new-line { + display: block; + height: 1px; + outline: none; + position: fixed; + top: 0; + z-index: 1 +} + + .jodit-add-new-line, .jodit-add-new-line * { + box-sizing: border-box + } + + .jodit-add-new-line:after { + background-color: var(--jd-anl-color-new-line); + content: ""; + display: block; + height: 1px; + width: 100% + } + + .jodit-add-new-line span { + align-items: center; + background: var(--jd-color-background-button-hover-opacity30); + border: 1px solid var(--jd-anl-color-new-line); + cursor: pointer; + display: flex; + height: var(--jd-anl-handle-size); + justify-content: center; + left: var(--jd-anl-handle-offset); + position: absolute; + top: 0; + transform: translateY(-50%); + width: var(--jd-anl-handle-size) + } + + .jodit-add-new-line span:hover { + background: var(--jd-color-background-button-hover) + } + + .jodit-add-new-line svg { + width: calc(var(--jd-anl-handle-size)/2); + fill: var(--jd-anl-color-new-line) + } + +.jodit-source__mode .jodit-add-new-line { + display: none !important +} + +:root { + --jd-color-picker-cell-size: 24px +} + +.jodit-color-picker { + margin: 0; + text-align: left; + user-select: none +} + +.jodit-color-picker__group { + display: flex; + flex-wrap: wrap; + margin-bottom: calc(var(--jd-padding-default)/2); + max-width: calc(var(--jd-color-picker-cell-size)*10); + white-space: normal +} + +.jodit-color-picker__color-item { + border: 1px solid transparent; + display: block; + height: var(--jd-color-picker-cell-size); + text-align: center; + text-decoration: none; + vertical-align: middle; + width: var(--jd-color-picker-cell-size) +} + + .jodit-color-picker__color-item:hover { + border-color: #000 + } + + .jodit-color-picker__color-item:active, .jodit-color-picker__color-item_active_true { + border: 2px solid var(--jd-color-border-selected) + } + +.jodit-color-picker__native svg { + display: inline-block; + height: 16px; + margin-right: 4px; + width: 16px +} + +.jodit-color-picker__native input { + appearance: none; + border: none; + height: 18px; + padding: 0; + width: 18px +} + + .jodit-color-picker__native input[type=color]::-webkit-color-swatch-wrapper { + padding: 0 + } + + .jodit-color-picker__native input input[type=color]::-webkit-color-swatch { + border: none + } + +.jodit-tabs { + font-family: var(--jd-font-default); + font-size: var(--jd-font-size-default) +} + + .jodit-tabs .jodit-tabs__buttons { + display: flex; + justify-content: center; + margin-bottom: var(--jd-padding-default); + margin-top: calc(var(--jd-padding-default)/2) + } + + .jodit-tabs .jodit-tabs__buttons > * { + cursor: pointer; + margin-left: calc(var(--jd-padding-default)/2) + } + + .jodit-tabs .jodit-tabs__buttons > :only-of-type { + width: 100% + } + + .jodit-tabs .jodit-tabs__buttons > :first-child { + margin-left: 0 + } + +@media (max-width:480px) { + .jodit-tabs .jodit-tabs__buttons { + display: block + } + + .jodit-tabs .jodit-tabs__buttons > * { + margin-left: 0; + width: 100% + } +} + +.jodit-tabs__button { + min-width: 80px +} + +.jodit-tabs__button_columns_3 { + width: 33.33333% +} + +.jodit-tabs__button_columns_2 { + width: 50% +} + +.jodit-tabs .jodit-tabs__wrapper .jodit-tab { + display: none +} + + .jodit-tabs .jodit-tabs__wrapper .jodit-tab.jodit-tab_active { + display: block + } + + .jodit-tabs .jodit-tabs__wrapper .jodit-tab.jodit-tab_empty { + min-height: 100px; + min-width: 220px + } + +.jodit_fullsize-box_true { + overflow: visible !important; + position: static !important; + z-index: var(--jd-z-index-full-size) !important +} + +body.jodit_fullsize-box_true, html.jodit_fullsize-box_true { + height: 0 !important; + overflow: hidden !important; + width: 0 !important +} + +html.jodit_fullsize-box_true { + position: fixed !important +} + +.jodit_fullsize { + inset: 0; + max-width: none !important; + position: absolute; + z-index: var(--jd-z-index-full-size) +} + + .jodit_fullsize .toolbar { + width: 100% !important + } + + .jodit_fullsize .jodit__area, .jodit_fullsize .jodit_editor { + height: 100% + } + +.jodit-ui-image-position-tab__lockMargin > svg, .jodit-ui-image-position-tab__lockSize > svg, .jodit-ui-image-properties-form__lockMargin > svg, .jodit-ui-image-properties-form__lockSize > svg { + display: inline-block; + height: var(--jd-icon-middle-size); + overflow: hidden; + width: var(--jd-icon-middle-size); + fill: var(--jd-color-dark); + line-height: var(--jd-icon-middle-size); + transform-origin: 0 0 !important; + vertical-align: middle +} + +.jodit-ui-image-position-tab__view-box, .jodit-ui-image-properties-form__view-box { + padding: var(--jd-padding-default) +} + +.jodit-ui-image-position-tab__imageView, .jodit-ui-image-properties-form__imageView { + align-items: center; + background-color: var(--jd-color-background-light-gray); + display: flex; + height: var(--jd-width-default); + justify-content: center; + margin: 0 0 var(--jd-padding-default); + padding: 0 +} + + .jodit-ui-image-position-tab__imageView img, .jodit-ui-image-properties-form__imageView img { + max-height: 100%; + max-width: 100% + } + +.jodit-ui-image-position-tab__imageSizes.jodit-form__group, .jodit-ui-image-properties-form__imageSizes.jodit-form__group { + align-items: center; + flex-direction: row; + margin: 0; + min-width: auto; + padding: 0 +} + + .jodit-ui-image-position-tab__imageSizes.jodit-form__group a, .jodit-ui-image-properties-form__imageSizes.jodit-form__group a { + cursor: pointer; + display: inline-block + } + +.jodit-ui-image-position-tab .jodit-form__group, .jodit-ui-image-properties-form .jodit-form__group { + padding: 0 +} + +.jodit-ui-image-position-tab__tabsBox, .jodit-ui-image-properties-form__tabsBox { + padding: 0 var(--jd-padding-default) +} + +.jodit-ui-image-properties-form_lock_true:before { + background-color: var(--jd-color-button-background-hover-opacity60); + content: ""; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; + z-index: 3 +} + +.jodit-ui-image-properties-form_lock_true:after { + animation: b 2s ease-out 0s infinite; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAABRsSURBVHja7F1/aJfVGn/33RgUg8FiNfK2WCykyS7GLoYyUbwYipZMumgLo+iPS9HlXhSHkRXdislESxMz0mapuaFo2myjkfnNlTQ2FJdTu8NvLVcrdbpcfGvxrfs823m/vXt3fjznvOedzr0PPJzzPe+7d+97Ps95nuc851fGAw884CD98ccfI1Jqmc3UpEyQz4FkMqRTgYshn8fymZ57SyGbzf5mENIOz9+ngE9Atg/SLkhPQHoWeEDn3SmpSZlJnvf7ypUrTpb7IyMjY+gGN6WWmaY84l2T3c+u58D1csjOgvwsyBdBvsDRo2zgMl/ZNM59vcAJ4Dj8nzikLa5QmBLv28YCfPd3li7gPHBMwKdcEwhCJgN6FoLOWJtUgiWovALG04FXsbI44xbgw8AplbaU/Q+ZQNgGf0gA/JWhC1aQyle1eN91rPRKKKuEsjzZvSph0m2RiutpIYRrfZC8B+l7kB6jgq0CnQIy9X39v2NYQW5FeUFQlQVN/aALyiYBPw/5M5B+Dvw02vMggqcDukEl57F3xHf9H747+4bA5oD6dzqaYEgAqIDbBl9RhvZ4H/B5yL+IDp3oXhmwNkm3lTLn80VIz+O3QFqm2/rHwgeI6QDOa006LZ3Q4lHNNwK3AVeYAD4WgmHQUivYNzWyb7xufICYaavXVbuKZ6MXfwRVJ+TnXW+Am/oMnNaO3/Y5pPitcyh/a6LqtXwAt+J01LVFEzAJ0jpIj7JunJYd1wHchnBQHUSC3Uan8WPgPVgHlBiBCcAkH4Da2i2DjwGZlcy5W0K17zLwVb9NgaY4iJpawJs+BCnWwUo3SKXT4oOAP8IHCFsIfMCguj8JaQ2kOaaA227d10ALuIR1gHVxErjctPtHBd8btSR3A4MIgSePAZxqVPeQlthq7ZRuZVABCVkLuGkJpGgKsY4ybfUEVO84qhsoAzSgrUfHZ1UQVe99B6o2oMYdwg7latAq5iROGoueQExW6UE0gCe/ANIh9SZ6jqkWsN3STZ0rHWEgpkNmEvILxqQbSAXaAPxqSBswQkbpbpo6fGPR0m3GBYjBIIwqNjCTEAr4wkBQUA0AjKNrdZCu0okAqgQhTKCDhFxV91BNgsDuYx3WQZptG3xtDUCJEDKvthGuLVEJlq4gUMyAylfQERadPrhKOHTmB3Ces4RFEXNsgW8UClbZcEhxqPQIpHOord2k1ZsAH4YvYNJXN3EgWX4Ocw4LbIEvDQSJfADJtULWxSuj+BBUP4DaC6D0DkyFg6JKTVo/5brvXqzbo2zSi3af3/9bGgrW1Ar5kH4MXEzVHEHVf5CuYZC4fti9AoI/gXX8Eda5Tp9f9I4xWWsnOoc5zNMv1okjmKp/vzay3epNJ4+YmALdoWBPWTHksc5zTU1AekqYt7LcWTruTYTZQdmQHoB0GuXv/de8L8e7xrsuA8kPNtx3AZIOxp3APc7wvD6kvi+//DLh3nvPPfegWs1jf4dBGGxpOA+hlOXzgw7VBjEBnDKcs4jzDOZDOmjqD2SJQFGBx9JaSOcQ7xVO2RIJhf86AfB+Z3huHs7Ra2pra+ugtubTp0+jMLgC0e6/ftddd6EgzMO5iGwSaq4NITCdLczy6GzXAj8KnDIxAaM0AKeViwCtgbRSNgGUJwQyDaACngO4w6S/CXgb8KEvvvgiFUaw59y5c64mWXvnnXdmsijdYxjpdP6cXh6oS0g1Bb48zpFEzValA3663pcuXaoleSzFltBIlWhRmWx+v6yMcQJ4PU7A/Oyzz/qca0R33HEHrjlAEJa73rns24JqA0keTUGTjglIJpNOxsMPP6wLfiGkx53hxRbcewwXc1BAx0u4gGMNcP2nn36acq4juv322ytZ5K7UlhBo5LER3AvcTXU60wKgYbsyWTCi3LTV6wLvKesGrvrkk0/qneucCgoKHoJkHbxvYRAhMMij/zMbVzZRTMAvv/wycj4AoRv4Mk7oII4HkLp+vC6drwxt/FrgKeMBfKTe3t69UMFTgPG9B3WcQdMeBsvjhJJqnYGqjMrKSmr/tZxNWAi87o9i+1l5O6SPNjc3dzrjlPLz83HyC/aWpqk0gWZUUHZtJvxuUZmAtAYgtHycr/a6qIXz2DQI5OH1UDRjPIOPdOHChU6o+JmQXW+68JYS4vUB/bozvN5RGAImdwPZA3AC51RKrMAfyBHFGCRBnz4oe7ypqemgc4PQxYsX0YytuOWWW3BRaa3DWd0U1A/w/Z4KvBx4jcoExAitE6dzPStr3RR/QKQ5fOUJ4PsaGxtvGPC9dOnSJfyu+7ALa9MJFPx+lkU05YNBBDVdg0uwKc4eAWCZ83cC8jM+/PDDLucGpr6+Pvy+GWz/ASs9AMFvd7ax1ATEFOBjmLdSBraN3gBwHHhmQ0NDrzMB6PLly73MUYubOs3EiB/GJebyTEB6QogCnGrV6KAFR7AVeP4HH3ww4EwgunLlCn7vfACi1UQDqMb5PWUvm5qAB3HESXNomKz2GaOHv/DAgQNJZwJSf38/fvdC3J5G1iPQnf3jK5sGvx80MQHP69hxHWZ/2wN8//vvv3/BmcD0008/XWCaoEcUJ6C0eoUWeFbXBOBCzTKKJ2/YExgEXrRv374eJyLn6tWrWA+LAJRBy+o/rQUQUx0TsFwzRKzLK/bu3dseQf8nDQwMYH2sCOL0ibx9Vr6cagIKmf0nxe8pguC7vn/Pnj2bIshH088//4z1st+m+veUI6ZFFBOwLGj/XqIh0O4/HkEtJgDmcZ4/EED9e69VKk0ACoDN1u/jqrq6uv4IZjElk0msnypbwPs0wTKVCUBnYbLuMC5REA7v3r37vQhikhBgPTWrTAEFeB9NZt3C0SbAr/6DdPM4jF7/PyNotUzBU26vgAo8x+7zri3jmgAgnOJdKYrVB9QEb+zcubMrgpVOv/76K9bXGzrACwTJfw1D+9k8EzAXOE8GviEPAK+JIDXSAlhvA7yWTWztvMfiXM65PBNQrgLfUBi2v/vuu70RnPo0ODjYC0BtN3D2VNfLR5gAz04eRn17yb0p4A0RlIEI6y+la/MV1xf4fYACSEtDiP031dbWRrY/AP32229dAGCTrs1XrHHEaesFXh+gXCfooyEM2yIIrdC2ADZ/1D1eM+CagHLJ5ExTxrl9hyLsrDiDWI99EjApgPvLRwhAmQh4HV/Axwe3bt06GMEXnFKpFK4tOBgQcH95WdoEAE01nc8Xi8VEArA3gs4q7VWpfsHaCpEg4GrnoeXhOEKUw3u4yZYqbGo4Lk2KR5hZpcOsXjO9GIm0AYFycTErmoDJVLWu0Tto3bJly0CEmT36/fffkzh/UKfVE3yLkix3Xx+v5FjYaaslgiwUZxDrdbrm38guF6EAFFKAF5kEwcFPrRFcoVCrIdAiKsSlYUWqFi/zBwTXOiKsQqGOIKe1cQRmSAPkmYIv0ADY9Yuif+GYgC5Wv9kB1L6X8lAA8k3BFwhB94YNG1IRXPYJutwpINwBpNjSI/O5AhDQGUxEUIVKCRMBEGiFIQG4yX+Daf+fPacvwihUM2Czfm/KcgMLtjZZhudEY//hks2VVJlZ7tJvi5SMMApVA9gMsOVkXYvDFiO6fggFACUqJ6qKcaMBbD5uAH2AlE0fIKJxRSnUAGizcykePtWzjOo1VA2gpa0V2CVRALBbURDwQV4qiGAKVQDyLZ571JfFum0lFqTJvScvgilUytPxAxSY9boawMbD3OtFEUahaoAinQap0gA4JSzhPswSFz733HOZEVT2KZlMYr0WesGV7KpOoQRqgG6DVi4rx5EqjFWfjSCz3vqLHd9IoGyYnoBjNwpAwhBoWXlpJAChCECpv66p5ycJBCSBcwI7daZ7E83FtAiuUGgaT/WLACaYhk4MBCVk0UDKWb2c3+URVqFogOm8OqccqMW5d+Dmm29OuGsDOyw7gmUvvfRSFBCySFevXsX6LBO1cIoG8NEQ5u7KoFbLi0Kz3fODI7JGeHbwTSJADcxCq1cAWnR39yYIQUWEmVX1X2G6SYTgnhavABwL0uoF91dUV1dnR9AFp/7+fjysq0IGvIEGODYkAOwa7t/XYXl3kDzgBRF8Vgg3eczT2SqGYP97vBoA83ELrd6/WPSJCDsr6v8Jw91BRdfS6za9ewQ1qVo9RQv47plXU1NTHEFoTpcvX8aTwueJgKdoAI4wpE8Y9e4SdtgdGLK4S1gm8L8jGAO1fqy/TNmiUE1hQIwPj9AADOQk7ugRdJ9ADj+2bt26aI6AAV26dAnr7THqnsFEYTgEnBRtFl0fwk6hOcCrIjiNaBXOAKIcuq3hG4w4fTXma+lNOEHEZFs4hcA8+eqrr0a+gAZdvHgRbf+TsrMDDMxBr2v/eT7A0L5+8HN7AKdPFhncHMGqZftfB84Wga0yBwKtsN1hk4B5PsCIrd0C2HwRz924cWNlBK2afvzxx0rX89c5Qo4gCNv85bwDI7r8XUKqynfL/KmHazZt2pQbQSymH374AffuqeEB7gWXCrzHFCCmXf5niE4NWxPkJFAJ41GmtRHMUtWP9TNJdYScgQZYo3NoFEYF21WmgAq8776KzZs3Px1BPZq+//57rJcKXhg3oClo90b/qCeHvqLjA2j6B+u2bNlSFkH+J3333XdlAMo6ntq3cJroK6K4gOzgyP2oBaj2nqIdPGXYKzjw5ptvToqgd5yenh5U+Qcgmy07UdxQA7QD7xfFClSnh68Oelag6H5n+Fj6j9566638iQz++fPn8wGMRq/dV4EviwVwrq0W9QpUJsAdINof5LRQxfNLgBu2bt06IaePffvttzjDp8EZ3r6dDL7sQEkfyAdVW82rjo9H/hdkB2y2ft89eEB149tvvz2hlqh/8803OazlTzMFX6ENcKLvU7LgEMUEuIc9vqLb+inBJE8ezyo+un379gkxaPT111/jdx4FEGbJwOd1A2VdQ9896Pj1qIJDMSJI6yHpNGnpGlHFqVgp77zzzg29tjCRSBQx8KfKWrmJBvDkO4HXU3oI7pQwFUDpc/8s9ABk14uB23bs2HFDTiU7d+7cAqj4NrbESxtojeAQYjWoOnyaqwF4AsFSnDm81lT1y2YZ+cpwLmHDzp07a3bt2nVDTCrt6urKBq5hDl8eBXCTHgGjtWxTaVK8IEYFjKWrvVPIdU8VE2kMgUCsBD6ye/fukvEM/ldffVUCFX4EsitVtl3UYjU0wDHg1dQIodQJFJShKXgE0j5dLaACn6MJkKcDH6+rq6uur68fV72EM2fO5Jw9e7YasseBp5u0cKoQsDxO9Vrqqn6R2hdGAjWEoBvSR03B9wPNA95HGDVcBXxqz549D40H8E+fPo3vecoZntGTreqzmwgBRyDw2Plu3TBxxmuvvcYFUQYwy+OQ5UoV6DITQzEJnGsdbLSyfvHixdfVptSnTp2qZMJaqtsVVtWbAiP0zap498ryt956q5OxYcMGyj/gpbhbxS5IlwSJBQQYYsZVzWtREBYtWnTN9ic+efIkOq1LmM9SZDKplioQgrJ6ZpZTVODd32kBIEoZL0UvvdFdCBoUfGo8gXM0/UHgHTireeHChaFrhePHj+N0dzxqdxnwg2xwS0vD6YIvwAOnd89nvhkZeJduu+02J2Pjxo0UKZO9GM7w+cjdFMIgCmiqAXj39bO5DPFYLNY8b948ayeXtLW1lbIT1mcxzjVZUGtqCjh44Bj/34H7ZXjJhCItAAHAd1Mc0fvcPYAqCPhBhIHDF5jP0MF2QkmwE02HTMjs2bPTpqOlpSXPVeHABSwoVcLsOebzTWZH2fADOClO7ZqB3yfDTWUSUACyiHZG9UJY0SiNH7PKIjsiqt6BooegIhTMOYxHUTweN3q26EAN/wkr3t+qvEaKczbvxzoXPcf7brL/a9oNFKXYPZzpnUpGlX6dbqHIDIRNlIWXsuibbjdQkGLdzoQ0YfJ/uJFAamsndllw19HZzDlxVGFmkcqilFnSEFotnnKNOlZPGQX0lWOdzoa01xR47nCwDtBEpwbHoedj94wy0KSKCOoIQhgaQrXZgkoYdMCXPAvrcr57WITuXEHlcLCu00cQGjza7BEcRjbRAFSNQAXXVAh0zuY1BV/Q2r3pekixnz+oGRomvVtMV9Vr3I/98RXAC73LzoM4grIWb1sIxgp8iSnAOlsIKdZhynB8QG8wiKIBDPyCQ5C9F0cRKY6gDFwZ2DaFIEzwCS3e3b/nXlzKras1dFr/KA2go/5FLVRwfzdzDtfodgupZoFqGohbqIYGPsH+Yx3NxF6V7D2omkXlmMZM1T8PDMXfoUl4BruKkHaaaANbtj2MnoEJ+L6/72RdvGe8Kt9kjqBOj4SsAUyvce7BCSV/Ba6C/EBYXcSg5oIKtqkj5ikbgLSKqfwWaheRWqZ6j1gIAFPuQW2AI3lTIN0b1CSonMSwYgCU6wqQ8NunsOHcQcozVKZIVwhiKjVuMEihY0YwevgPSDG0eUy3ezjWYOsEhRRAHWPf/A93Egc1MKTj+FGEIGZhIEgJiMzPYPlmHNxgjmLTtRSCsOw+o2YWzcNvbTYIBVsVgrQGsAW+6cCSJx9nUcS/QbrfVAjCDgQZ/P1+yOM33Q9pPMizqCaAKgSxsMCntk6B2sdVyYsh/QvwC7hriY4QhCkUGi0e3/kF/AYow29pJ8YArJkAihDEwgRfVyNw8rif7X+B74Y8qs03nOGNDq0IgQ3Afff0sXecAfm72bv3UFoxpdWbtH7V32cFcfgoLcyCEKQdJ9zVHNL/AM9ijOP808MYD/CP7UvuO8ZGP+OMB3nP4T1PNfYvey/KXAPKd2XpevA27iWYANk9g8yZamblOa5A4FQtZ/jEsjybWsBTaX1sQkbcA/iACAQd0E2EQgU8RUiyKC02qGnQjS6qwPP9LQJwiLFLuUwQcBuaIiYQuBjTPc8wk/32VtYJFq104xQnmLlJMPuNNr3fUEuQQtDUVm8DeNcc/F+AAQBKd8HaIWdjwQAAAABJRU5ErkJggg==) no-repeat 50%; + background-size: 100% 100%; + background-size: var(--jd-icon-loader-size); + content: ""; + display: inline-block; + height: var(--jd-icon-loader-size); + left: 50%; + margin-left: -10px; + margin-top: -10px; + position: absolute; + top: 50%; + vertical-align: middle; + width: var(--jd-icon-loader-size); + will-change: transform +} + +.jodit-popup-inline__container { + min-width: 700px; + z-index: 1300 +} + +.jodit-paste-storage { + max-width: 600px; + padding: var(--jd-padding-default) +} + +@media (max-width:768px) { + .jodit-paste-storage { + max-width: 100% + } +} + +.jodit-paste-storage > div { + border: 1px solid var(--jd-color-border); + max-height: 300px; + max-width: 100% +} + + .jodit-paste-storage > div:first-child { + margin-bottom: var(--jd-padding-default) + } + + .jodit-paste-storage > div:first-child a { + border: 1px solid transparent; + box-sizing: border-box; + color: var(--jd-color-default); + display: block; + margin: 0; + max-width: 100%; + outline: none; + overflow: hidden; + padding: calc(var(--jd-padding-default)/2); + text-decoration: none; + text-overflow: ellipsis; + white-space: pre + } + + .jodit-paste-storage > div:first-child a.jodit_active { + background-color: var(--jd-dark-background-color); + color: var(--jd-color-white) + } + + .jodit-paste-storage > div:first-child a:focus { + outline: none + } + + .jodit-paste-storage > div:last-child { + overflow: auto; + padding: var(--jd-padding-default) + } + + .jodit-paste-storage > div:last-child li, .jodit-paste-storage > div:last-child ul { + margin: 0 + } + +.jodit-placeholder { + color: var(--jd-color-placeholder); + display: block; + left: 0; + padding: var(--jd-padding-default); + pointer-events: none; + position: absolute; + top: 0; + user-select: none !important; + width: 100%; + z-index: 1 +} + +.jodit__preview-box table { + border: none; + border-collapse: collapse; + empty-cells: show; + margin-bottom: 1em; + margin-top: 1em; + max-width: 100% +} + + .jodit__preview-box table tr { + user-select: none + } + + .jodit__preview-box table tr td, .jodit__preview-box table tr th { + border: 1px solid var(--jd-color-border); + min-width: 2em; + padding: .4em; + user-select: text; + vertical-align: middle + } + +.jodit-table-resizer { + cursor: col-resize; + margin-left: calc(var(--jd-padding-default)/-2); + padding-left: calc(var(--jd-padding-default)/2); + padding-right: calc(var(--jd-padding-default)/2); + position: absolute; + z-index: 3 +} + + .jodit-table-resizer:after { + border: 0; + content: ""; + display: block; + height: 100%; + width: 0 + } + +.jodit-table-resizer_moved { + background-color: var(--jd-color-background-selection); + z-index: 2 +} + + .jodit-table-resizer_moved:after { + border-right: 1px solid moved + } + +[data-jodit_iframe_wrapper] { + display: block; + position: relative; + user-select: none +} + + [data-jodit_iframe_wrapper] iframe { + position: relative + } + + [data-jodit_iframe_wrapper]:after { + background: transparent; + content: ""; + cursor: pointer; + display: block; + inset: 0; + position: absolute; + z-index: 1 + } + + [data-jodit_iframe_wrapper][data-jodit-wrapper_active=true] iframe { + z-index: 2 + } + +.jodit_lock [data-jodit-wrapper_active=true] iframe { + z-index: 1 +} + +:root { + --jd-viewer-width: 70px; + --jd-viewer-height: 24px; + --jd-resizer-handle-size: 10px; + --jd-resizer-border-color: #98c1f1; + --jd-resizer-handle-color: #5ba4f3; + --jd-resizer-handle-hover-color: #537ebb +} + +.jodit-resizer { + font-size: 0; + height: 100px; + left: 0; + outline: 3px solid var(--jd-resizer-border-color); + pointer-events: none; + position: absolute; + top: 0; + width: 100px +} + + .jodit-resizer, .jodit-resizer * { + box-sizing: border-box + } + + .jodit-resizer > span { + background-color: var(--jd-color-placeholder); + color: var(--jd-color-white); + display: inline-block; + font-size: 12px; + height: var(--jd-viewer-height); + left: 50%; + line-height: var(--jd-viewer-height); + margin-left: calc(var(--jd-viewer-width)/-2); + margin-top: calc(var(--jd-viewer-height)/-2); + opacity: 0; + overflow: visible; + position: absolute; + text-align: center; + top: 50%; + transition: opacity .2s linear; + width: var(--jd-viewer-width) + } + + .jodit-resizer > div { + background-color: var(--jd-resizer-handle-color); + display: inline-block; + height: var(--jd-resizer-handle-size); + pointer-events: all; + position: absolute; + width: var(--jd-resizer-handle-size); + z-index: 4 + } + + .jodit-resizer > div:hover { + background-color: var(--jd-resizer-handle-hover-color) + } + + .jodit-resizer > div:first-child { + cursor: nwse-resize; + left: calc(var(--jd-resizer-handle-size)/-2); + top: calc(var(--jd-resizer-handle-size)/-2) + } + + .jodit-resizer > div:nth-child(2) { + cursor: nesw-resize; + right: calc(var(--jd-resizer-handle-size)/-2); + top: calc(var(--jd-resizer-handle-size)/-2) + } + + .jodit-resizer > div:nth-child(3) { + bottom: calc(var(--jd-resizer-handle-size)/-2); + cursor: nwse-resize; + right: calc(var(--jd-resizer-handle-size)/-2) + } + + .jodit-resizer > div:nth-child(4) { + bottom: calc(var(--jd-resizer-handle-size)/-2); + cursor: nesw-resize; + left: calc(var(--jd-resizer-handle-size)/-2) + } + +@media (max-width:768px) { + .jodit-resizer > div :root { + --jd-resizer-handle-size: calc(var(--jd-resizer-handle-size)*2) + } +} + +:root { + --jd-height-search: 30px; + --jd-width-search: 320px; + --jd-width-search-input-box: 60%; + --jd-width-search-count-box: 15%; + --jd-transform-button-active: 0.95; + --jd-timeout-button-active: 0.1s +} + +.jodit-ui-search { + height: 0; + position: absolute; + right: 0; + top: 0; + width: 0 +} + +.jodit-ui-search_sticky_true { + position: fixed +} + +.jodit-ui-search__box { + background-color: var(--jd-color-panel); + border: solid var(--jd-color-border); + border-width: 0 0 1px 1px; + display: flex; + max-width: 100vw; + padding: calc(var(--jd-padding-default)/2); + position: absolute; + right: 0; + width: var(--jd-width-search) +} + + .jodit-ui-search__box input { + background-color: transparent; + border: 0; + height: 100%; + margin: 0; + outline: none; + padding: 0 var(--jd-padding-default); + width: 100% + } + + .jodit-ui-search__box input[data-ref=replace] { + display: none + } + + .jodit-ui-search__box input:not(:focus) + input:not(:focus) { + border-top: 1px solid var(--jd-color-border) + } + +.jodit-ui-search__buttons, .jodit-ui-search__counts, .jodit-ui-search__inputs { + height: var(--jd-height-search) +} + +.jodit-ui-search__inputs { + padding-right: calc(var(--jd-padding-default)/2); + width: var(--jd-width-search-input-box) +} + +.jodit-ui-search__counts { + border-left: 1px solid var(--jd-color-border); + color: var(--jd-color-border); + width: var(--jd-width-search-count-box) +} + +.jodit-ui-search__buttons, .jodit-ui-search__counts { + align-items: center; + display: flex; + justify-content: center +} + +.jodit-ui-search__buttons { + flex: 1; + padding-left: 0 +} + + .jodit-ui-search__buttons button { + background-color: transparent; + border: 1px solid transparent; + height: 100%; + margin-right: 1%; + width: 32% + } + + .jodit-ui-search__buttons button[data-ref=replace-btn] { + border: 1px solid var(--jd-color-border); + display: none; + margin-top: 2px; + width: 100% + } + + .jodit-ui-search__buttons button:hover { + background-color: var(--jd-color-background-button-hover) + } + + .jodit-ui-search__buttons button:focus { + border: 1px solid var(--jd-color-background-selection-opacity50) + } + + .jodit-ui-search__buttons button:active { + border: 1px solid var(--jd-color-background-selection); + transform: scale(var(--jd-transform-button-active)) + } + +.jodit-ui-search_empty-query_true [data-ref=next], .jodit-ui-search_empty-query_true [data-ref=prev] { + opacity: .5 +} + +.jodit-ui-search_replace_true .jodit-ui-search__counts, .jodit-ui-search_replace_true .jodit-ui-search__inputs { + height: calc(var(--jd-height-search)*2) +} + + .jodit-ui-search_replace_true .jodit-ui-search__counts input, .jodit-ui-search_replace_true .jodit-ui-search__inputs input { + height: 50%; + transition: background-color var(--jd-timeout-button-active) linear + } + + .jodit-ui-search_replace_true .jodit-ui-search__counts input:focus, .jodit-ui-search_replace_true .jodit-ui-search__inputs input:focus { + box-shadow: inset 0 0 3px 0 var(--jd-color-border) + } + + .jodit-ui-search_replace_true .jodit-ui-search__counts input[data-ref=replace], .jodit-ui-search_replace_true .jodit-ui-search__inputs input[data-ref=replace] { + display: block + } + +.jodit-ui-search_replace_true .jodit-ui-search__buttons { + flex-wrap: wrap +} + + .jodit-ui-search_replace_true .jodit-ui-search__buttons button[data-ref=replace-btn] { + display: block + } + +::highlight(jodit-search-result), [jd-tmp-selection] { + background-color: var(--jd-color-background-selection); + color: var(--jd-color-text-selection) +} + +.jodit-container:not(.jodit_inline) { + min-height: 100px +} + + .jodit-container:not(.jodit_inline) .jodit-workplace { + display: flex; + flex-direction: column; + height: auto; + min-height: 50px; + overflow: hidden + } + + .jodit-container:not(.jodit_inline) .jodit-editor__resize { + position: relative + } + + .jodit-container:not(.jodit_inline) .jodit-editor__resize svg { + bottom: 0; + cursor: nwse-resize; + height: 12px; + overflow: hidden; + position: absolute; + right: 0; + width: 12px; + fill: var(--jd-color-gray-dark); + user-select: none + } + +.jodit-source { + background-color: var(--jd-color-source-area); + display: none; + flex: auto; + overflow: auto; + position: relative +} + + .jodit-source, .jodit-source .jodit-source__mirror-fake { + min-height: 100% + } + + .jodit-source * { + font: 12px/normal Monaco,Menlo,Ubuntu Mono,Consolas,source-code-pro,monospace + } + +.jodit-container.jodit-source__mode .jodit-wysiwyg, .jodit-container.jodit-source__mode .jodit-wysiwyg_iframe { + display: none !important +} + +.jodit-container.jodit-source__mode .jodit-source { + display: block !important +} + +.jodit-container.jodit_split_mode .jodit-workplace { + flex-flow: row nowrap +} + +.jodit-container.jodit_split_mode .jodit-source, .jodit-container.jodit_split_mode .jodit-wysiwyg, .jodit-container.jodit_split_mode .jodit-wysiwyg_iframe { + display: block !important; + flex: 1; + width: 50% +} + +.jodit-source__mirror { + background: var(--jd-color-source-area); + border: 0; + box-shadow: none; + box-sizing: border-box; + color: #f0f0f0; + height: 100%; + line-height: 1.5; + font: 12px/normal Monaco,Menlo,Ubuntu Mono,Consolas,source-code-pro,monospace; + margin: 0; + min-height: 100%; + outline: none; + overflow: auto; + padding: var(--jd-padding-default); + resize: none; + tab-size: 2em; + white-space: pre-wrap; + width: 100%; + z-index: 2 +} + + .jodit-source__mirror::selection { + background: var(--jd-color-selection-area) + } + +.jodit_sticky-dummy_toolbar { + display: none +} + +.jodit_sticky > .jodit-toolbar__box { + border-bottom: 1px solid var(--jd-color-border); + left: auto; + position: fixed; + position: sticky; + top: 0; + z-index: 3 +} + +.jodit_sticky .jodit_sticky-dummy_toolbar { + display: block +} + +.jodit-symbols { + padding: var(--jd-padding-default); + width: 460px +} + +.jodit-symbols__container { + display: flex +} + +.jodit-symbols__container_table { + width: 88% +} + +.jodit-symbols__container_preview { + width: 12% +} + +.jodit-symbols__preview { + border: 1px solid var(--jd-color-border); + font-size: 34px; + padding: 20px 0; + text-align: center +} + +.jodit-symbols__table { + border: 0; + border-spacing: 0; + table-layout: fixed +} + + .jodit-symbols__table td { + padding: 0 + } + + .jodit-symbols__table td a { + border: 1px solid transparent; + box-sizing: border-box; + color: var(--jd-color-text); + cursor: pointer; + display: inline-block; + font-size: 16px; + height: calc(var(--jd-height-element-default)*1.2); + line-height: calc(var(--jd-height-element-default)*1.2); + text-align: center; + text-decoration: none; + vertical-align: top; + width: calc(var(--jd-width-element-default)*1.2) + } + + .jodit-symbols__table td a:focus, .jodit-symbols__table td a:hover { + outline: 2px solid var(--jd-color-border) + } + +.jodit-ui-ai-assistant { + min-width: 460px; + padding: var(--jd-padding-default); + width: 100% +} + +@media (max-width:768px) { + .jodit-ui-ai-assistant { + min-width: 100% + } +} + +.jodit-ui-ai-assistant__body { + margin-bottom: 10px +} + +.jodit-ui-ai-assistant__prompt-row { + align-items: flex-start; + display: flex; + margin-bottom: 10px +} + +.jodit-ui-ai-assistant__prompt-row-label { + margin-right: 10px +} + +.jodit-ui-ai-assistant__prompt-row-input { + flex: 1; + margin-right: 10px +} + +.jodit-ui-ai-assistant__prompt-row .jodit-icon_ai_assistant { + cursor: pointer; + height: 22px; + width: 22px +} + +.jodit-ui-ai-assistant__prompt-row .jodit-ui-button { + margin-right: 10px +} + +.jodit-ui-ai-assistant__prompt-row .jodit-ui-button_ai_assistant { + margin-right: 0; + margin-top: 20px +} + +.jodit-ui-ai-assistant__results { + border-color: var(--jd-color-label); + border-style: solid; + border-width: 1px; + height: 300px; + line-height: 1.5; + max-width: 460px; + min-height: 300px; + min-width: 100%; + overflow: auto; + padding: var(--jd-padding-default); + position: relative +} + + .jodit-ui-ai-assistant__results p { + margin: 0 0 10px + } + +.jodit-ui-ai-assistant__close { + cursor: pointer; + padding: 10px; + position: absolute; + right: 0; + top: 0 +} + +.jodit-ui-ai-assistant_hide_true { + display: none +} + +.jodit-ui-ai-assistant__spinner:before { + animation: b .6s linear infinite; + border: 1px solid #ccc; + border-radius: 50%; + border-top-color: #8817c3; + box-sizing: border-box; + content: ""; + height: 30px; + left: 50%; + margin-left: -15px; + margin-top: -15px; + position: absolute; + top: 50%; + width: 30px +} + +.jodit-ui-ai-assistant__error { + color: var(--jd-color-error) +} + +/*.jodit-context table, .jodit-wysiwyg table { + border: none; + border-collapse: collapse; + empty-cells: show; + margin-bottom: 1em; + margin-top: 1em; + max-width: 100% +} + + .jodit-context table tr, .jodit-wysiwyg table tr { + user-select: none + } + + .jodit-context table tr td, .jodit-context table tr th, .jodit-wysiwyg table tr td, .jodit-wysiwyg table tr th { + border: 1px solid var(--jd-color-border); + min-width: 2em; + padding: .4em; + user-select: text; + vertical-align: middle + }*/ + +.jodit-form__inserter { + --jd-color-table-cell-background-hover: var(--jd-color-button-background-hover) +} + + .jodit-form__inserter .jodit-form__table-creator-box { + display: flex + } + +@media (max-width:768px) { + .jodit-form__inserter .jodit-form__table-creator-box { + flex-direction: column + } +} + +.jodit-form__inserter .jodit-form__table-creator-box .jodit-form__container { + font-size: 0; + margin: 0; + min-width: 180px; + padding: 0 +} + + .jodit-form__inserter .jodit-form__table-creator-box .jodit-form__container > div > span { + border: 1px solid var(--jd-color-border); + box-sizing: border-box; + display: inline-block; + height: var(--jd-height-element-default); + margin-bottom: 2px; + margin-left: 2px; + vertical-align: top; + width: var(--jd-width-element-default) + } + + .jodit-form__inserter .jodit-form__table-creator-box .jodit-form__container > div > span:first-child { + margin-left: 0 + } + + .jodit-form__inserter .jodit-form__table-creator-box .jodit-form__container > div > span.jodit_hovered { + background: var(--jd-color-table-cell-background-hover); + border-color: var(--jd-color-table-cell-background-hover) + } + +.jodit-form__inserter .jodit-form__table-creator-box .jodit-form__options { + font-size: var(--jd-font-size-default) +} + + .jodit-form__inserter .jodit-form__table-creator-box .jodit-form__options label { + padding-top: 0; + text-align: left + } + + .jodit-form__inserter .jodit-form__table-creator-box .jodit-form__options label input { + margin-right: var(--jd-padding-default) + } + +.jodit-form__inserter label { + font-size: 14px; + margin: 0; + padding: 8px; + text-align: center +} + +.jodit-xpath { + align-items: center; + display: flex; + margin-left: calc(var(--jd-padding-default)/-2) +} + +.jodit-xpath__item { + display: flex; + height: var(--jd-font-size-small); + line-height: calc(var(--jd-font-size-small) - 1px) +} + + .jodit-xpath__item a { + color: var(--jd-color-default); + font-size: var(--jd-font-size-small); + margin-left: 2px; + outline: 0; + padding: 0 3px + } + +:root { + --jd-color-white: #fff; + --jd-color-gray: #dadada; + --jd-color-gray-dark: #a5a5a5; + --jd-color-dark: #4c4c4c; + --jd-color-blue: #b5d6fd; + --jd-color-light-blue: rgba(181,214,253,.5); + --jd-color-red: #ff3b3b; + --jd-color-light-red: rgba(255,59,59,.4); + --jd-color-default: var(--jd-color-dark); + --jd-color-text: #222; + --jd-color-label: var(--jd-color-gray-dark); + --jd-color-error: var(--jd-color-red); + --jd-color-border: var(--jd-color-gray); + --jd-color-border-dark: var(--jd-color-dark); + --jd-color-border-selected: #1e88e5; + --jd-color-border-active: #b5b5b5; + --jd-color-selection: var(--jd-color-dark); + --jd-color-selection-area: #bdbdbd; + --jd-color-separator: var(--jd-color-border); + --jd-color-placeholder: var(--jd-color-gray-dark); + --jd-color-panel: #f9f9f9; + --jd-color-resizer: #c8c8c8; + --jd-color-background-default: var(--jd-color-white); + --jd-color-background-light-gray: #f5f5f6; + --jd-color-background-gray: var(--jd-color-gray); + --jd-color-background-gray-hover: #f8f8f8; + --jd-color-background-button-hover: #ecebe9; + --jd-color-background-button-hover-opacity30: hsla(40,7%,92%,.3); + --jd-color-background-progress: #b91f1f; + --jd-color-background-active: #2196f3; + --jd-color-background-selection: #b5d6fd; + --jd-color-text-selection: var(--jd-color-white); + --jd-color-background-selection-opacity50: rgba(181,214,253,.995); + --jd-color-source-area: #323232; + --jd-color-button-background-hover: #dcdcdc; + --jd-color-button-background-hover-opacity40: hsla(0,0%,86%,.4); + --jd-color-button-background-hover-opacity60: hsla(0,0%,86%,.6); + --jd-font-default: -apple-system,blinkmacsystemfont,"Segoe UI",roboto,oxygen-sans,ubuntu,cantarell,"Helvetica Neue",sans-serif; + --jd-font-size-default: 14px; + --jd-font-size-small: 11px; + --jd-color-text-icons: rgba(0,0,0,.75); + --jd-color-icon: var(--jd-color-dark); + --jd-padding-default: 8px; + --jd-border-radius-default: 3px; + --jd-icon-tiny-size: 8px; + --jd-icon-xsmall-size: 10px; + --jd-icon-small-size: 12px; + --jd-icon-middle-size: 14px; + --jd-icon-large-size: 16px; + --jd-z-index-full-size: 100000; + --jd-z-index-popup: 10000001; + --jd-z-index-dialog-overlay: 20000003; + --jd-z-index-dialog: 20000004; + --jd-z-index-context-menu: 30000005; + --jd-z-index-tooltip: 30000006; + --jd-icon-loader-size: 48px; + --jd-width-element-default: 18px; + --jd-height-element-default: 18px; + --jd-dark-background-color: #575757; + --jd-dark-background-ligher: silver; + --jd-dark-background-darknes: #353535; + --jd-dark-border-color: #444; + --jd-dark-text-color: #d1cccc; + --jd-dark-text-color-opacity80: hsla(0,5%,81%,.8); + --jd-dark-text-color-opacity50: hsla(0,5%,81%,.5); + --jd-dark-icon-color: silver; + --jd-dark-toolbar-color: #5f5c5c; + --jd-dark-toolbar-seperator-color1: rgba(81,81,81,.41); + --jd-dark-toolbar-seperator-color2: #686767; + --jd-dark-toolbar-seperator-color-opacity80: hsla(0,0%,41%,.8); + --jd-dark-toolbar-seperator-color3: hsla(0,0%,41%,.75); + --jd-dark-color-border-selected: #152f5f; + --jd-width-default: 180px; + --jd-width-input-min: var(--jd-width-default); + --jd-input-height: 32px; + --jd-button-icon-size: 14px; + --jd-margin-v: 2px; + --jd-button-df-size: calc((var(--jd-button-icon-size) - 4px)*2); + --jd-button-size: calc(var(--jd-button-icon-size) + var(--jd-button-df-size) + var(--jd-margin-v)*2); + --jd-focus-input-box-shadow: 0 0 0 0.05rem rgba(0,123,255,.25) +} + +.jodit-wysiwyg { + outline: 0 +} + + .jodit-wysiwyg ::selection, .jodit-wysiwyg::selection { + background: #b5d6fd; + color: #4c4c4c + } + +.jodit-container:not(.jodit_inline) .jodit-wysiwyg { + margin: 0; + outline: 0; + overflow-x: auto; + padding: 8px; + position: relative +} + + .jodit-container:not(.jodit_inline) .jodit-wysiwyg img { + max-width: 100%; + position: relative + } + + .jodit-container:not(.jodit_inline) .jodit-wysiwyg jodit-media { + position: relative + } + + .jodit-container:not(.jodit_inline) .jodit-wysiwyg jodit-media * { + position: relative; + z-index: 0 + } + + .jodit-container:not(.jodit_inline) .jodit-wysiwyg jodit-media:before { + content: ""; + inset: 0; + position: absolute; + z-index: 1 + } + +:root { + --jd-switche-width: 60px; + --jd-switche-height: 32px; + --jd-switche-slider-margin: 4px; + --jd-switche-slider-size: calc(var(--jd-switche-height) - var(--jd-switche-slider-margin)*2) +} + +.jodit-form { + color: var(--jd-color-default); + font-family: var(--jd-font-default); + font-size: var(--jd-font-size-default) +} + + .jodit-form.jodit_error { + border-color: var(--jd-color-error); + box-shadow: inset 0 0 3px 0 hsla(0,0%,74%,.3) + } + +@media (max-width:768px) { + .jodit-form { + min-width: 150px + } +} + +.jodit-form button { + background: #d6d6d6; + border: none; + color: var(--jd-color-dark); + cursor: pointer; + font-size: 16px; + height: 36px; + line-height: 1; + margin-bottom: var(--jd-padding-default); + margin-top: var(--jd-padding-default); + outline: none; + padding: var(--jd-padding-default); + text-decoration: none; + transition: background .2s ease 0s +} + + .jodit-form button:hover { + background-color: var(--jd-color-background-button-hover); + color: var(--jd-color-dark) + } + + .jodit-form button:active { + background: var(--jd-color-background-button-hover); + color: var(--jd-color-dark) + } + +.jodit-form label { + align-items: center; + display: flex; + margin-bottom: var(--jd-padding-default); + text-align: left; + white-space: nowrap +} + + .jodit-form label:last-child { + margin-bottom: 0 + } + +.jodit-form .jodit-form__center { + justify-content: center +} + +.jodit .jodit-input, .jodit .jodit-select, .jodit .jodit-textarea { + appearance: none; + background-color: var(--jd-color-white); + border: 1px solid var(--jd-color-border); + border-radius: 0; + box-sizing: border-box; + font-family: var(--jd-font-default); + font-size: var(--jd-font-size-default); + height: var(--jd-input-height); + line-height: 1.2; + outline: none; + padding: 0 var(--jd-padding-default); + width: 100% +} + + .jodit .jodit-input[disabled], .jodit .jodit-select[disabled], .jodit .jodit-textarea[disabled] { + background-color: #f0f0f0; + color: var(--jd-color-border) + } + +.jodit .jodit-input_has-error_true, .jodit .jodit-select_has-error_true, .jodit .jodit-textarea_has-error_true { + border-color: var(--jd-color-red) +} + +.jodit .jodit-input:focus { + border-color: #66afe9; + outline: 0 +} + +.jodit-checkbox { + border: 0; + cursor: pointer; + height: 16px; + margin: 0 calc(var(--jd-padding-default)/2) 0 0; + outline: none; + padding: 0; + position: relative; + width: 16px; + z-index: 2 +} + +.jodit-select { + background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' id='Layer_1' data-name='Layer 1' viewBox='0 0 4.95 10'%3E%3Cdefs%3E%3Cstyle%3E.cls-2{fill:%23444}%3C/style%3E%3C/defs%3E%3Cpath d='M0 0h4.95v10H0z' style='fill:%23fff'/%3E%3Cpath d='m1.41 4.67 1.07-1.49 1.06 1.49zM3.54 5.33 2.48 6.82 1.41 5.33z' class='cls-2'/%3E%3C/svg%3E"); + background-position: 98% 50%; + background-repeat: no-repeat; + padding-right: calc(var(--jd-padding-default)*2) +} + +.jodit-textarea { + height: auto +} + +.jodit-form__group, .jodit-textarea { + min-width: var(--jd-width-input-min) +} + +.jodit-form__group { + display: flex; + flex-direction: column; + margin-bottom: var(--jd-padding-default) +} + + .jodit-form__group label { + margin-bottom: calc(var(--jd-padding-default)/2) + } + +.jodit-button { + align-items: center; + background-color: var(--jd-color-background-gray); + border: 0; + border-radius: .25rem; + color: var(--jd-color-default); + cursor: pointer; + display: inline-flex; + height: calc(var(--jd-padding-default)*4); + justify-content: center; + line-height: 1; + margin: 0; + padding: 0 var(--jd-padding-default); + position: relative; + text-decoration: none; + user-select: none; + width: auto +} + + .jodit-button svg { + display: inline-block; + height: 24px; + width: 24px + } + + .jodit-button svg + span { + margin-left: calc(var(--jd-padding-default)/2) + } + + .jodit-button:active, .jodit-button:focus { + outline: 0 + } + + .jodit-button.disabled { + opacity: .7 + } + +.jodit-buttons { + display: flex; + flex-wrap: nowrap; + justify-content: space-between; + margin-bottom: var(--jd-padding-default) +} + +.jodit-button .jodit_icon, .jodit-button svg, .jodit-dialog__header .jodit_icon, .jodit-dialog__header svg { + display: inline-block; + height: 16px; + vertical-align: middle; + width: 16px +} + +.jodit-switcher-wrapper { + align-items: center; + display: flex +} + + .jodit-switcher-wrapper .jodit-switcher + span { + margin-left: var(--jd-padding-default) + } + +.jodit-switcher { + display: inline-block; + height: var(--jd-switche-height); + position: relative; + width: var(--jd-switche-width) +} + + .jodit-switcher input { + height: 0; + opacity: 0; + width: 0 + } + + .jodit-switcher .jodit-switcher__slider { + background-color: var(--jd-color-gray); + border-radius: var(--jd-switche-height); + cursor: pointer; + inset: 0; + position: absolute; + transition: .4s + } + + .jodit-switcher .jodit-switcher__slider:before { + background-color: #fff; + border-radius: 50%; + bottom: var(--jd-switche-slider-margin); + content: ""; + height: var(--jd-switche-slider-size); + left: var(--jd-switche-slider-margin); + position: absolute; + transition: .4s; + width: var(--jd-switche-slider-size) + } + +input:checked + .jodit-switcher__slider { + background-color: var(--jd-color-background-active) +} + + input:checked + .jodit-switcher__slider:before { + transform: translateX(calc(var(--jd-switche-width) - var(--jd-switche-slider-margin)*2 - var(--jd-switche-slider-size))) + } + +input:focus + .jodit-switcher__slider { + box-shadow: 0 0 1px var(--jd-color-background-active) +} + +.jodit-button-group { + display: flex +} + + .jodit-button-group input { + display: none + } + + .jodit-button-group button { + display: flex; + flex: 1; + justify-content: center; + text-align: center + } + + .jodit-button-group button + button { + margin-left: -1px + } + + .jodit-button-group button:first-child, .jodit-button-group input:first-child + button { + border-bottom-right-radius: 0; + border-right: 0; + border-top-right-radius: 0 + } + + .jodit-button-group button:last-child, .jodit-button-group input:last-child + button { + border-bottom-left-radius: 0; + border-left: 0; + border-top-left-radius: 0 + } + + .jodit-button-group input[type=checkbox]:checked + button, .jodit-button-group input[type=checkbox]:not(:checked) + button + button { + background-image: none; + box-shadow: inset 0 2px 4px rgba(0,0,0,.3),0 1px 2px rgba(0,0,0,.05) + } + +.jodit_text_icons .jodit_icon { + font-size: var(--jd-font-size-default); + width: auto +} + + .jodit_text_icons .jodit_icon:first-letter { + text-transform: uppercase + } + +.jodit_text_icons .jodit-tabs .jodit-tabs__buttons > a { + font-family: var(--jd-font-default); + width: auto +} + + .jodit_text_icons .jodit-tabs .jodit-tabs__buttons > a i { + width: auto + } + +.jodit_text_icons.jodit-dialog .jodit-button, .jodit_text_icons.jodit-dialog .jodit-dialog__header a { + color: var(--jd-color-text-icons); + font-family: var(--jd-font-default); + padding: var(--jd-padding-default); + width: auto +} + + .jodit_text_icons.jodit-dialog .jodit-button .jodit_icon, .jodit_text_icons.jodit-dialog .jodit-dialog__header a .jodit_icon { + width: auto + } + +.jodit-grid { + display: flex; + width: 100% +} + + .jodit-grid.jodit-grid_column { + flex-direction: column + } + +@media (max-width:480px) { + .jodit-grid.jodit-grid_xs-column { + flex-direction: column + } +} + +.jodit-grid [class*=jodit_col-] { + flex: 1 1 auto +} + +.jodit-grid .jodit_col-lg-5-5 { + width: 100% +} + +.jodit-grid .jodit_col-lg-4-5 { + width: 80% +} + +.jodit-grid .jodit_col-lg-3-5 { + width: 60% +} + +.jodit-grid .jodit_col-lg-2-5 { + width: 40% +} + +.jodit-grid .jodit_col-lg-1-5 { + width: 20% +} + +.jodit-grid .jodit_col-lg-4-4 { + width: 100% +} + +.jodit-grid .jodit_col-lg-3-4 { + width: 75% +} + +.jodit-grid .jodit_col-lg-2-4 { + width: 50% +} + +.jodit-grid .jodit_col-lg-1-4 { + width: 25% +} + +@media (max-width:992px) { + .jodit-grid .jodit_col-md-5-5 { + width: 100% + } + + .jodit-grid .jodit_col-md-4-5 { + width: 80% + } + + .jodit-grid .jodit_col-md-3-5 { + width: 60% + } + + .jodit-grid .jodit_col-md-2-5 { + width: 40% + } + + .jodit-grid .jodit_col-md-1-5 { + width: 20% + } + + .jodit-grid .jodit_col-md-4-4 { + width: 100% + } + + .jodit-grid .jodit_col-md-3-4 { + width: 75% + } + + .jodit-grid .jodit_col-md-2-4 { + width: 50% + } + + .jodit-grid .jodit_col-md-1-4 { + width: 25% + } +} + +@media (max-width:768px) { + .jodit-grid .jodit_col-sm-5-5 { + width: 100% + } + + .jodit-grid .jodit_col-sm-4-5 { + width: 80% + } + + .jodit-grid .jodit_col-sm-3-5 { + width: 60% + } + + .jodit-grid .jodit_col-sm-2-5 { + width: 40% + } + + .jodit-grid .jodit_col-sm-1-5 { + width: 20% + } + + .jodit-grid .jodit_col-sm-4-4 { + width: 100% + } + + .jodit-grid .jodit_col-sm-3-4 { + width: 75% + } + + .jodit-grid .jodit_col-sm-2-4 { + width: 50% + } + + .jodit-grid .jodit_col-sm-1-4 { + width: 25% + } +} + +@media (max-width:480px) { + .jodit-grid .jodit_col-xs-5-5 { + width: 100% + } + + .jodit-grid .jodit_col-xs-4-5 { + width: 80% + } + + .jodit-grid .jodit_col-xs-3-5 { + width: 60% + } + + .jodit-grid .jodit_col-xs-2-5 { + width: 40% + } + + .jodit-grid .jodit_col-xs-1-5 { + width: 20% + } + + .jodit-grid .jodit_col-xs-4-4 { + width: 100% + } + + .jodit-grid .jodit_col-xs-3-4 { + width: 75% + } + + .jodit-grid .jodit_col-xs-2-4 { + width: 50% + } + + .jodit-grid .jodit_col-xs-1-4 { + width: 25% + } +} + +@keyframes b { + to { + transform: rotate(1turn) + } +} + +.jodit-icon_loader { + animation: b 2s ease-out 0s infinite; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAABRsSURBVHja7F1/aJfVGn/33RgUg8FiNfK2WCykyS7GLoYyUbwYipZMumgLo+iPS9HlXhSHkRXdislESxMz0mapuaFo2myjkfnNlTQ2FJdTu8NvLVcrdbpcfGvxrfs823m/vXt3fjznvOedzr0PPJzzPe+7d+97Ps95nuc851fGAw884CD98ccfI1Jqmc3UpEyQz4FkMqRTgYshn8fymZ57SyGbzf5mENIOz9+ngE9Atg/SLkhPQHoWeEDn3SmpSZlJnvf7ypUrTpb7IyMjY+gGN6WWmaY84l2T3c+u58D1csjOgvwsyBdBvsDRo2zgMl/ZNM59vcAJ4Dj8nzikLa5QmBLv28YCfPd3li7gPHBMwKdcEwhCJgN6FoLOWJtUgiWovALG04FXsbI44xbgw8AplbaU/Q+ZQNgGf0gA/JWhC1aQyle1eN91rPRKKKuEsjzZvSph0m2RiutpIYRrfZC8B+l7kB6jgq0CnQIy9X39v2NYQW5FeUFQlQVN/aALyiYBPw/5M5B+Dvw02vMggqcDukEl57F3xHf9H747+4bA5oD6dzqaYEgAqIDbBl9RhvZ4H/B5yL+IDp3oXhmwNkm3lTLn80VIz+O3QFqm2/rHwgeI6QDOa006LZ3Q4lHNNwK3AVeYAD4WgmHQUivYNzWyb7xufICYaavXVbuKZ6MXfwRVJ+TnXW+Am/oMnNaO3/Y5pPitcyh/a6LqtXwAt+J01LVFEzAJ0jpIj7JunJYd1wHchnBQHUSC3Uan8WPgPVgHlBiBCcAkH4Da2i2DjwGZlcy5W0K17zLwVb9NgaY4iJpawJs+BCnWwUo3SKXT4oOAP8IHCFsIfMCguj8JaQ2kOaaA227d10ALuIR1gHVxErjctPtHBd8btSR3A4MIgSePAZxqVPeQlthq7ZRuZVABCVkLuGkJpGgKsY4ybfUEVO84qhsoAzSgrUfHZ1UQVe99B6o2oMYdwg7latAq5iROGoueQExW6UE0gCe/ANIh9SZ6jqkWsN3STZ0rHWEgpkNmEvILxqQbSAXaAPxqSBswQkbpbpo6fGPR0m3GBYjBIIwqNjCTEAr4wkBQUA0AjKNrdZCu0okAqgQhTKCDhFxV91BNgsDuYx3WQZptG3xtDUCJEDKvthGuLVEJlq4gUMyAylfQERadPrhKOHTmB3Ces4RFEXNsgW8UClbZcEhxqPQIpHOord2k1ZsAH4YvYNJXN3EgWX4Ocw4LbIEvDQSJfADJtULWxSuj+BBUP4DaC6D0DkyFg6JKTVo/5brvXqzbo2zSi3af3/9bGgrW1Ar5kH4MXEzVHEHVf5CuYZC4fti9AoI/gXX8Eda5Tp9f9I4xWWsnOoc5zNMv1okjmKp/vzay3epNJ4+YmALdoWBPWTHksc5zTU1AekqYt7LcWTruTYTZQdmQHoB0GuXv/de8L8e7xrsuA8kPNtx3AZIOxp3APc7wvD6kvi+//DLh3nvPPfegWs1jf4dBGGxpOA+hlOXzgw7VBjEBnDKcs4jzDOZDOmjqD2SJQFGBx9JaSOcQ7xVO2RIJhf86AfB+Z3huHs7Ra2pra+ugtubTp0+jMLgC0e6/ftddd6EgzMO5iGwSaq4NITCdLczy6GzXAj8KnDIxAaM0AKeViwCtgbRSNgGUJwQyDaACngO4w6S/CXgb8KEvvvgiFUaw59y5c64mWXvnnXdmsijdYxjpdP6cXh6oS0g1Bb48zpFEzValA3663pcuXaoleSzFltBIlWhRmWx+v6yMcQJ4PU7A/Oyzz/qca0R33HEHrjlAEJa73rns24JqA0keTUGTjglIJpNOxsMPP6wLfiGkx53hxRbcewwXc1BAx0u4gGMNcP2nn36acq4juv322ytZ5K7UlhBo5LER3AvcTXU60wKgYbsyWTCi3LTV6wLvKesGrvrkk0/qneucCgoKHoJkHbxvYRAhMMij/zMbVzZRTMAvv/wycj4AoRv4Mk7oII4HkLp+vC6drwxt/FrgKeMBfKTe3t69UMFTgPG9B3WcQdMeBsvjhJJqnYGqjMrKSmr/tZxNWAi87o9i+1l5O6SPNjc3dzrjlPLz83HyC/aWpqk0gWZUUHZtJvxuUZmAtAYgtHycr/a6qIXz2DQI5OH1UDRjPIOPdOHChU6o+JmQXW+68JYS4vUB/bozvN5RGAImdwPZA3AC51RKrMAfyBHFGCRBnz4oe7ypqemgc4PQxYsX0YytuOWWW3BRaa3DWd0U1A/w/Z4KvBx4jcoExAitE6dzPStr3RR/QKQ5fOUJ4PsaGxtvGPC9dOnSJfyu+7ALa9MJFPx+lkU05YNBBDVdg0uwKc4eAWCZ83cC8jM+/PDDLucGpr6+Pvy+GWz/ASs9AMFvd7ax1ATEFOBjmLdSBraN3gBwHHhmQ0NDrzMB6PLly73MUYubOs3EiB/GJebyTEB6QogCnGrV6KAFR7AVeP4HH3ww4EwgunLlCn7vfACi1UQDqMb5PWUvm5qAB3HESXNomKz2GaOHv/DAgQNJZwJSf38/fvdC3J5G1iPQnf3jK5sGvx80MQHP69hxHWZ/2wN8//vvv3/BmcD0008/XWCaoEcUJ6C0eoUWeFbXBOBCzTKKJ2/YExgEXrRv374eJyLn6tWrWA+LAJRBy+o/rQUQUx0TsFwzRKzLK/bu3dseQf8nDQwMYH2sCOL0ibx9Vr6cagIKmf0nxe8pguC7vn/Pnj2bIshH088//4z1st+m+veUI6ZFFBOwLGj/XqIh0O4/HkEtJgDmcZ4/EED9e69VKk0ACoDN1u/jqrq6uv4IZjElk0msnypbwPs0wTKVCUBnYbLuMC5REA7v3r37vQhikhBgPTWrTAEFeB9NZt3C0SbAr/6DdPM4jF7/PyNotUzBU26vgAo8x+7zri3jmgAgnOJdKYrVB9QEb+zcubMrgpVOv/76K9bXGzrACwTJfw1D+9k8EzAXOE8GviEPAK+JIDXSAlhvA7yWTWztvMfiXM65PBNQrgLfUBi2v/vuu70RnPo0ODjYC0BtN3D2VNfLR5gAz04eRn17yb0p4A0RlIEI6y+la/MV1xf4fYACSEtDiP031dbWRrY/AP32229dAGCTrs1XrHHEaesFXh+gXCfooyEM2yIIrdC2ADZ/1D1eM+CagHLJ5ExTxrl9hyLsrDiDWI99EjApgPvLRwhAmQh4HV/Axwe3bt06GMEXnFKpFK4tOBgQcH95WdoEAE01nc8Xi8VEArA3gs4q7VWpfsHaCpEg4GrnoeXhOEKUw3u4yZYqbGo4Lk2KR5hZpcOsXjO9GIm0AYFycTErmoDJVLWu0Tto3bJly0CEmT36/fffkzh/UKfVE3yLkix3Xx+v5FjYaaslgiwUZxDrdbrm38guF6EAFFKAF5kEwcFPrRFcoVCrIdAiKsSlYUWqFi/zBwTXOiKsQqGOIKe1cQRmSAPkmYIv0ADY9Yuif+GYgC5Wv9kB1L6X8lAA8k3BFwhB94YNG1IRXPYJutwpINwBpNjSI/O5AhDQGUxEUIVKCRMBEGiFIQG4yX+Daf+fPacvwihUM2Czfm/KcgMLtjZZhudEY//hks2VVJlZ7tJvi5SMMApVA9gMsOVkXYvDFiO6fggFACUqJ6qKcaMBbD5uAH2AlE0fIKJxRSnUAGizcykePtWzjOo1VA2gpa0V2CVRALBbURDwQV4qiGAKVQDyLZ571JfFum0lFqTJvScvgilUytPxAxSY9boawMbD3OtFEUahaoAinQap0gA4JSzhPswSFz733HOZEVT2KZlMYr0WesGV7KpOoQRqgG6DVi4rx5EqjFWfjSCz3vqLHd9IoGyYnoBjNwpAwhBoWXlpJAChCECpv66p5ycJBCSBcwI7daZ7E83FtAiuUGgaT/WLACaYhk4MBCVk0UDKWb2c3+URVqFogOm8OqccqMW5d+Dmm29OuGsDOyw7gmUvvfRSFBCySFevXsX6LBO1cIoG8NEQ5u7KoFbLi0Kz3fODI7JGeHbwTSJADcxCq1cAWnR39yYIQUWEmVX1X2G6SYTgnhavABwL0uoF91dUV1dnR9AFp/7+fjysq0IGvIEGODYkAOwa7t/XYXl3kDzgBRF8Vgg3eczT2SqGYP97vBoA83ELrd6/WPSJCDsr6v8Jw91BRdfS6za9ewQ1qVo9RQv47plXU1NTHEFoTpcvX8aTwueJgKdoAI4wpE8Y9e4SdtgdGLK4S1gm8L8jGAO1fqy/TNmiUE1hQIwPj9AADOQk7ugRdJ9ADj+2bt26aI6AAV26dAnr7THqnsFEYTgEnBRtFl0fwk6hOcCrIjiNaBXOAKIcuq3hG4w4fTXma+lNOEHEZFs4hcA8+eqrr0a+gAZdvHgRbf+TsrMDDMxBr2v/eT7A0L5+8HN7AKdPFhncHMGqZftfB84Wga0yBwKtsN1hk4B5PsCIrd0C2HwRz924cWNlBK2afvzxx0rX89c5Qo4gCNv85bwDI7r8XUKqynfL/KmHazZt2pQbQSymH374AffuqeEB7gWXCrzHFCCmXf5niE4NWxPkJFAJ41GmtRHMUtWP9TNJdYScgQZYo3NoFEYF21WmgAq8776KzZs3Px1BPZq+//57rJcKXhg3oClo90b/qCeHvqLjA2j6B+u2bNlSFkH+J3333XdlAMo6ntq3cJroK6K4gOzgyP2oBaj2nqIdPGXYKzjw5ptvToqgd5yenh5U+Qcgmy07UdxQA7QD7xfFClSnh68Oelag6H5n+Fj6j9566638iQz++fPn8wGMRq/dV4EviwVwrq0W9QpUJsAdINof5LRQxfNLgBu2bt06IaePffvttzjDp8EZ3r6dDL7sQEkfyAdVW82rjo9H/hdkB2y2ft89eEB149tvvz2hlqh/8803OazlTzMFX6ENcKLvU7LgEMUEuIc9vqLb+inBJE8ezyo+un379gkxaPT111/jdx4FEGbJwOd1A2VdQ9896Pj1qIJDMSJI6yHpNGnpGlHFqVgp77zzzg29tjCRSBQx8KfKWrmJBvDkO4HXU3oI7pQwFUDpc/8s9ABk14uB23bs2HFDTiU7d+7cAqj4NrbESxtojeAQYjWoOnyaqwF4AsFSnDm81lT1y2YZ+cpwLmHDzp07a3bt2nVDTCrt6urKBq5hDl8eBXCTHgGjtWxTaVK8IEYFjKWrvVPIdU8VE2kMgUCsBD6ye/fukvEM/ldffVUCFX4EsitVtl3UYjU0wDHg1dQIodQJFJShKXgE0j5dLaACn6MJkKcDH6+rq6uur68fV72EM2fO5Jw9e7YasseBp5u0cKoQsDxO9Vrqqn6R2hdGAjWEoBvSR03B9wPNA95HGDVcBXxqz549D40H8E+fPo3vecoZntGTreqzmwgBRyDw2Plu3TBxxmuvvcYFUQYwy+OQ5UoV6DITQzEJnGsdbLSyfvHixdfVptSnTp2qZMJaqtsVVtWbAiP0zap498ryt956q5OxYcMGyj/gpbhbxS5IlwSJBQQYYsZVzWtREBYtWnTN9ic+efIkOq1LmM9SZDKplioQgrJ6ZpZTVODd32kBIEoZL0UvvdFdCBoUfGo8gXM0/UHgHTireeHChaFrhePHj+N0dzxqdxnwg2xwS0vD6YIvwAOnd89nvhkZeJduu+02J2Pjxo0UKZO9GM7w+cjdFMIgCmiqAXj39bO5DPFYLNY8b948ayeXtLW1lbIT1mcxzjVZUGtqCjh44Bj/34H7ZXjJhCItAAHAd1Mc0fvcPYAqCPhBhIHDF5jP0MF2QkmwE02HTMjs2bPTpqOlpSXPVeHABSwoVcLsOebzTWZH2fADOClO7ZqB3yfDTWUSUACyiHZG9UJY0SiNH7PKIjsiqt6BooegIhTMOYxHUTweN3q26EAN/wkr3t+qvEaKczbvxzoXPcf7brL/a9oNFKXYPZzpnUpGlX6dbqHIDIRNlIWXsuibbjdQkGLdzoQ0YfJ/uJFAamsndllw19HZzDlxVGFmkcqilFnSEFotnnKNOlZPGQX0lWOdzoa01xR47nCwDtBEpwbHoedj94wy0KSKCOoIQhgaQrXZgkoYdMCXPAvrcr57WITuXEHlcLCu00cQGjza7BEcRjbRAFSNQAXXVAh0zuY1BV/Q2r3pekixnz+oGRomvVtMV9Vr3I/98RXAC73LzoM4grIWb1sIxgp8iSnAOlsIKdZhynB8QG8wiKIBDPyCQ5C9F0cRKY6gDFwZ2DaFIEzwCS3e3b/nXlzKras1dFr/KA2go/5FLVRwfzdzDtfodgupZoFqGohbqIYGPsH+Yx3NxF6V7D2omkXlmMZM1T8PDMXfoUl4BruKkHaaaANbtj2MnoEJ+L6/72RdvGe8Kt9kjqBOj4SsAUyvce7BCSV/Ba6C/EBYXcSg5oIKtqkj5ikbgLSKqfwWaheRWqZ6j1gIAFPuQW2AI3lTIN0b1CSonMSwYgCU6wqQ8NunsOHcQcozVKZIVwhiKjVuMEihY0YwevgPSDG0eUy3ezjWYOsEhRRAHWPf/A93Egc1MKTj+FGEIGZhIEgJiMzPYPlmHNxgjmLTtRSCsOw+o2YWzcNvbTYIBVsVgrQGsAW+6cCSJx9nUcS/QbrfVAjCDgQZ/P1+yOM33Q9pPMizqCaAKgSxsMCntk6B2sdVyYsh/QvwC7hriY4QhCkUGi0e3/kF/AYow29pJ8YArJkAihDEwgRfVyNw8rif7X+B74Y8qs03nOGNDq0IgQ3Afff0sXecAfm72bv3UFoxpdWbtH7V32cFcfgoLcyCEKQdJ9zVHNL/AM9ijOP808MYD/CP7UvuO8ZGP+OMB3nP4T1PNfYvey/KXAPKd2XpevA27iWYANk9g8yZamblOa5A4FQtZ/jEsjybWsBTaX1sQkbcA/iACAQd0E2EQgU8RUiyKC02qGnQjS6qwPP9LQJwiLFLuUwQcBuaIiYQuBjTPc8wk/32VtYJFq104xQnmLlJMPuNNr3fUEuQQtDUVm8DeNcc/F+AAQBKd8HaIWdjwQAAAABJRU5ErkJggg==) no-repeat 50%; + background-size: 100% 100%; + display: inline-block; + height: var(--jd-icon-loader-size); + vertical-align: middle; + width: var(--jd-icon-loader-size); + will-change: transform +} + +.jodit-icon { + background: 50% no-repeat; + background-size: contain; + height: 14px; + overflow: visible; + width: 14px; + fill: var(--jd-color-icon); + transform-origin: 0 0 !important +} + +.jodit-icon, .jodit-icon_close { + stroke: var(--jd-color-icon) +} + +svg.jodit-icon { + height: auto; + isolation: isolate +} + +.jodit-icon_text { + font-size: 14px +} + +.jodit, .jodit *, .jodit-container, .jodit-container * { + box-sizing: border-box +} + + .jodit .jodit-workplace, .jodit-container .jodit-workplace { + overflow: auto; + position: relative + } + + .jodit .jodit-workplace .jodit-wysiwyg, .jodit .jodit-workplace .jodit-wysiwyg_iframe, .jodit-container .jodit-workplace .jodit-wysiwyg, .jodit-container .jodit-workplace .jodit-wysiwyg_iframe { + height: 100%; + width: 100% + } + +.jodit-wysiwyg [contenteditable=false] { + cursor: default +} + +.jodit-container:not(.jodit_inline) { + background-color: var(--jd-color-background-light-gray); + border: 1px solid var(--jd-color-border); + border-radius: var(--jd-border-radius-default) +} + + .jodit-container:not(.jodit_inline) .jodit-workplace { + background-color: var(--jd-color-background-default); + border: 0 solid var(--jd-color-border); + max-height: 100% + } + + .jodit-container:not(.jodit_inline).jodit_disabled { + background: var(--jd-color-background-gray) + } + + .jodit-container:not(.jodit_inline).jodit_disabled .jodit-workplace { + opacity: .4 + } + +.jodit_disabled, .jodit_lock { + user-select: none !important +} + +.jodit_hidden { + display: none !important +} + +.jodit_vertical_middle { + align-items: center; + display: flex +} + +.jodit-box { + background: 0 0; + border: 0; + float: none; + height: auto; + margin: 0; + max-width: none; + outline: 0; + padding: 0; + position: static; + width: auto +} + +.jodit-dialog_theme_dark, .jodit_theme_dark { + --jd-color-border: #6b6b6b; + --jd-color-text: var(--jd-dark-text-color) +} + + .jodit-dialog_theme_dark .jodit-toolbar-collection_mode_horizontal, .jodit-dialog_theme_dark .jodit-toolbar-editor-collection_mode_horizontal, .jodit_theme_dark .jodit-toolbar-collection_mode_horizontal, .jodit_theme_dark .jodit-toolbar-editor-collection_mode_horizontal { + background-image: repeating-linear-gradient(transparent 0,transparent calc(var(--jd-button-size) - 1px),var(--jd-color-border) var(--jd-button-size)) + } + + .jodit-dialog_theme_dark .jodit-toolbar-collection_mode_horizontal:after, .jodit-dialog_theme_dark .jodit-toolbar-editor-collection_mode_horizontal:after, .jodit_theme_dark .jodit-toolbar-collection_mode_horizontal:after, .jodit_theme_dark .jodit-toolbar-editor-collection_mode_horizontal:after { + background-color: var(--jd-color-border) + } + + .jodit-dialog_theme_dark .jodit-toolbar__box:not(:empty), .jodit_theme_dark .jodit-toolbar__box:not(:empty) { + border-color: var(--jd-color-border) + } + + .jodit-dialog_theme_dark .jodit-toolbar__box:not(:empty) .jodit-toolbar-editor-collection:after, .jodit_theme_dark .jodit-toolbar__box:not(:empty) .jodit-toolbar-editor-collection:after { + background-color: var(--jd-color-border) + } + + .jodit-dialog_theme_dark .jodit-ui-group_separated_true:not(:last-child,.jodit-ui-group_before-spacer_true):after, .jodit_theme_dark .jodit-ui-group_separated_true:not(:last-child,.jodit-ui-group_before-spacer_true):after { + border-right-color: var(--jd-color-border) + } + + .jodit-dialog_theme_dark.jodit-container, .jodit_theme_dark.jodit-container { + background-color: var(--jd-dark-background-color); + border-color: var(--jd-color-border) + } + + .jodit-dialog_theme_dark.jodit-container.jodit_disabled, .jodit_theme_dark.jodit-container.jodit_disabled { + background-color: var(--jd-dark-background-color) + } + + .jodit-dialog_theme_dark.jodit-container:not(.jodit_inline) .jodit-workplace, .jodit_theme_dark.jodit-container:not(.jodit_inline) .jodit-workplace { + border-color: var(--jd-dark-background-color) + } + + .jodit-dialog_theme_dark .jodit-popup__content, .jodit_theme_dark .jodit-popup__content { + background: var(--jd-dark-background-color) + } + + .jodit-dialog_theme_dark .jodit-toolbar-button, .jodit-dialog_theme_dark .jodit-toolbar-select, .jodit-dialog_theme_dark .jodit-ui-button, .jodit_theme_dark .jodit-toolbar-button, .jodit_theme_dark .jodit-toolbar-select, .jodit_theme_dark .jodit-ui-button { + --jd-color-icon: var(--jd-dark-icon-color) + } + + .jodit-dialog_theme_dark .jodit-toolbar-button__text, .jodit-dialog_theme_dark .jodit-toolbar-select__text, .jodit-dialog_theme_dark .jodit-ui-button__text, .jodit_theme_dark .jodit-toolbar-button__text, .jodit_theme_dark .jodit-toolbar-select__text, .jodit_theme_dark .jodit-ui-button__text { + color: var(--jd-color-text) + } + + .jodit-dialog_theme_dark .jodit-toolbar-button .jodit-icon, .jodit-dialog_theme_dark .jodit-toolbar-button svg, .jodit-dialog_theme_dark .jodit-toolbar-button__trigger, .jodit-dialog_theme_dark .jodit-toolbar-select .jodit-icon, .jodit-dialog_theme_dark .jodit-toolbar-select svg, .jodit-dialog_theme_dark .jodit-toolbar-select__trigger, .jodit-dialog_theme_dark .jodit-ui-button .jodit-icon, .jodit-dialog_theme_dark .jodit-ui-button svg, .jodit-dialog_theme_dark .jodit-ui-button__trigger, .jodit_theme_dark .jodit-toolbar-button .jodit-icon, .jodit_theme_dark .jodit-toolbar-button svg, .jodit_theme_dark .jodit-toolbar-button__trigger, .jodit_theme_dark .jodit-toolbar-select .jodit-icon, .jodit_theme_dark .jodit-toolbar-select svg, .jodit_theme_dark .jodit-toolbar-select__trigger, .jodit_theme_dark .jodit-ui-button .jodit-icon, .jodit_theme_dark .jodit-ui-button svg, .jodit_theme_dark .jodit-ui-button__trigger { + fill: var(--jd-color-icon); + stroke: var(--jd-color-icon) + } + + .jodit-dialog_theme_dark .jodit-toolbar-button:hover:not([disabled]), .jodit-dialog_theme_dark .jodit-toolbar-button__button:hover:not([disabled]), .jodit-dialog_theme_dark .jodit-toolbar-button__text:hover:not([disabled]), .jodit-dialog_theme_dark .jodit-toolbar-button__trigger:hover:not([disabled]), .jodit-dialog_theme_dark .jodit-toolbar-select:hover:not([disabled]), .jodit-dialog_theme_dark .jodit-toolbar-select__button:hover:not([disabled]), .jodit-dialog_theme_dark .jodit-toolbar-select__text:hover:not([disabled]), .jodit-dialog_theme_dark .jodit-toolbar-select__trigger:hover:not([disabled]), .jodit-dialog_theme_dark .jodit-ui-button:hover:not([disabled]), .jodit-dialog_theme_dark .jodit-ui-button__button:hover:not([disabled]), .jodit-dialog_theme_dark .jodit-ui-button__text:hover:not([disabled]), .jodit-dialog_theme_dark .jodit-ui-button__trigger:hover:not([disabled]), .jodit_theme_dark .jodit-toolbar-button:hover:not([disabled]), .jodit_theme_dark .jodit-toolbar-button__button:hover:not([disabled]), .jodit_theme_dark .jodit-toolbar-button__text:hover:not([disabled]), .jodit_theme_dark .jodit-toolbar-button__trigger:hover:not([disabled]), .jodit_theme_dark .jodit-toolbar-select:hover:not([disabled]), .jodit_theme_dark .jodit-toolbar-select__button:hover:not([disabled]), .jodit_theme_dark .jodit-toolbar-select__text:hover:not([disabled]), .jodit_theme_dark .jodit-toolbar-select__trigger:hover:not([disabled]), .jodit_theme_dark .jodit-ui-button:hover:not([disabled]), .jodit_theme_dark .jodit-ui-button__button:hover:not([disabled]), .jodit_theme_dark .jodit-ui-button__text:hover:not([disabled]), .jodit_theme_dark .jodit-ui-button__trigger:hover:not([disabled]) { + --jd-color-text: var(--jd-dark-background-color); + --jd-color-icon: var(--jd-dark-background-color); + background-color: var(--jd-dark-background-ligher); + color: var(--jd-dark-background-color) + } + + .jodit-dialog_theme_dark .jodit-status-bar, .jodit-dialog_theme_dark .jodit-workplace + .jodit-status-bar:not(:empty), .jodit_theme_dark .jodit-status-bar, .jodit_theme_dark .jodit-workplace + .jodit-status-bar:not(:empty) { + background-color: var(--jd-dark-toolbar-color); + border-color: var(--jd-color-border); + color: var(--jd-dark-text-color) + } + + .jodit-dialog_theme_dark .jodit-status-bar, .jodit-dialog_theme_dark .jodit-status-bar .jodit-status-bar__item a, .jodit-dialog_theme_dark .jodit-status-bar .jodit-status-bar__item span, .jodit-dialog_theme_dark .jodit-status-bar a.jodit-status-bar-link, .jodit-dialog_theme_dark .jodit-status-bar a.jodit-status-bar-link:hover, .jodit-dialog_theme_dark .jodit-status-bar a.jodit-status-bar-link:visited, .jodit-dialog_theme_dark .jodit-workplace + .jodit-status-bar:not(:empty), .jodit-dialog_theme_dark .jodit-workplace + .jodit-status-bar:not(:empty) .jodit-status-bar__item a, .jodit-dialog_theme_dark .jodit-workplace + .jodit-status-bar:not(:empty) .jodit-status-bar__item span, .jodit-dialog_theme_dark .jodit-workplace + .jodit-status-bar:not(:empty) a.jodit-status-bar-link, .jodit-dialog_theme_dark .jodit-workplace + .jodit-status-bar:not(:empty) a.jodit-status-bar-link:hover, .jodit-dialog_theme_dark .jodit-workplace + .jodit-status-bar:not(:empty) a.jodit-status-bar-link:visited, .jodit_theme_dark .jodit-status-bar, .jodit_theme_dark .jodit-status-bar .jodit-status-bar__item a, .jodit_theme_dark .jodit-status-bar .jodit-status-bar__item span, .jodit_theme_dark .jodit-status-bar a.jodit-status-bar-link, .jodit_theme_dark .jodit-status-bar a.jodit-status-bar-link:hover, .jodit_theme_dark .jodit-status-bar a.jodit-status-bar-link:visited, .jodit_theme_dark .jodit-workplace + .jodit-status-bar:not(:empty), .jodit_theme_dark .jodit-workplace + .jodit-status-bar:not(:empty) .jodit-status-bar__item a, .jodit_theme_dark .jodit-workplace + .jodit-status-bar:not(:empty) .jodit-status-bar__item span, .jodit_theme_dark .jodit-workplace + .jodit-status-bar:not(:empty) a.jodit-status-bar-link, .jodit_theme_dark .jodit-workplace + .jodit-status-bar:not(:empty) a.jodit-status-bar-link:hover, .jodit_theme_dark .jodit-workplace + .jodit-status-bar:not(:empty) a.jodit-status-bar-link:visited { + color: var(--jd-dark-text-color) + } + + .jodit-dialog_theme_dark .jodit-toolbar__box:not(:empty), .jodit_theme_dark .jodit-toolbar__box:not(:empty) { + background: var(--jd-dark-toolbar-color) + } + + .jodit-dialog_theme_dark .jodit-icon-close, .jodit_theme_dark .jodit-icon-close { + stroke: var(--jd-dark-icon-color) + } + + .jodit-dialog_theme_dark .jodit-wysiwyg, .jodit-dialog_theme_dark .jodit-wysiwyg_iframe, .jodit_theme_dark .jodit-wysiwyg, .jodit_theme_dark .jodit-wysiwyg_iframe { + background-color: var(--jd-dark-background-color); + color: var(--jd-dark-text-color) + } + + .jodit-dialog_theme_dark .jodit-form input[type=text], .jodit-dialog_theme_dark .jodit-form input[type=url], .jodit-dialog_theme_dark .jodit-form textarea, .jodit_theme_dark .jodit-form input[type=text], .jodit_theme_dark .jodit-form input[type=url], .jodit_theme_dark .jodit-form textarea { + background-color: var(--jd-dark-toolbar-seperator-color1); + border-color: var(--jd-dark-toolbar-seperator-color2); + color: var(--jd-dark-text-color) + } + + .jodit-dialog_theme_dark .jodit-form button, .jodit_theme_dark .jodit-form button { + background-color: var(--jd-dark-toolbar-seperator-color3); + color: var(--jd-dark-text-color) + } + + .jodit-dialog_theme_dark .jodit-placeholder, .jodit_theme_dark .jodit-placeholder { + color: var(--jd-dark-text-color-opacity80) + } + + .jodit-dialog_theme_dark .jodit-drag-and-drop__file-box, .jodit-dialog_theme_dark .jodit_uploadfile_button, .jodit_theme_dark .jodit-drag-and-drop__file-box, .jodit_theme_dark .jodit_uploadfile_button { + color: var(--jd-dark-text-color) + } + + .jodit-dialog_theme_dark .jodit-drag-and-drop__file-box:hover, .jodit-dialog_theme_dark .jodit_uploadfile_button:hover, .jodit_theme_dark .jodit-drag-and-drop__file-box:hover, .jodit_theme_dark .jodit_uploadfile_button:hover { + background-color: var(--jd-dark-toolbar-seperator-color3) + } + + .jodit-dialog_theme_dark .jodit-add-new-line:before, .jodit_theme_dark .jodit-add-new-line:before { + border-top-color: var(--jd-dark-toolbar-seperator-color2) + } + + .jodit-dialog_theme_dark .jodit-add-new-line span, .jodit_theme_dark .jodit-add-new-line span { + background: var(--jd-dark-toolbar-seperator-color3); + border-color: var(--jd-dark-toolbar-seperator-color2) + } + + .jodit-dialog_theme_dark .jodit-add-new-line span svg, .jodit_theme_dark .jodit-add-new-line span svg { + fill: var(--jd-dark-text-color) + } + + .jodit-dialog_theme_dark .jodit-resizer > i, .jodit_theme_dark .jodit-resizer > i { + background: var(--jd-dark-toolbar-seperator-color3); + border-color: var(--jd-dark-icon-color) + } + + .jodit-dialog_theme_dark .jodit-input, .jodit-dialog_theme_dark .jodit-select, .jodit_theme_dark .jodit-input, .jodit_theme_dark .jodit-select { + background-color: var(--jd-dark-background-ligher); + border-color: var(--jd-dark-border-color); + color: var(--jd-dark-border-color) + } + + .jodit-dialog_theme_dark.jodit-dialog, .jodit_theme_dark.jodit-dialog { + background-color: var(--jd-dark-background-color) + } + + .jodit-dialog_theme_dark.jodit-dialog .jodit-dialog__header, .jodit-dialog_theme_dark.jodit-dialog .jodit-filebrowser__files.active .jodit-filebrowser__files-item, .jodit_theme_dark.jodit-dialog .jodit-dialog__header, .jodit_theme_dark.jodit-dialog .jodit-filebrowser__files.active .jodit-filebrowser__files-item { + border-color: var(--jd-dark-border-color) + } + + .jodit-dialog_theme_dark.jodit-dialog .jodit-filebrowser__files.active .jodit-filebrowser__files-item-info, .jodit_theme_dark.jodit-dialog .jodit-filebrowser__files.active .jodit-filebrowser__files-item-info { + background-color: var(--jd-dark-text-color) + } diff --git a/Wino.Mail.WinUI/JS/libs/jodit.min.js b/Wino.Mail.WinUI/JS/libs/jodit.min.js new file mode 100644 index 00000000..75b640a5 --- /dev/null +++ b/Wino.Mail.WinUI/JS/libs/jodit.min.js @@ -0,0 +1,10 @@ +/*! + * jodit - Jodit is an awesome and useful wysiwyg editor with filebrowser + * Author: Chupurnov (https://xdsoft.net/jodit/) + * Version: v4.2.5 + * Url: https://xdsoft.net/jodit/ + * License(s): MIT + */ + + +((t,e)=>{if("object"==typeof exports&&"object"==typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var s=e();for(var i in s)("object"==typeof exports?exports:t)[i]=s[i]}})(self,(function(){return function(){var t,e={26318(t,e,s){"use strict";function i(t){return i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?t=>typeof t:t=>t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t,i(t)}function r(t,e,s){var r=s.value;if("function"!=typeof r)throw new TypeError("@boundMethod decorator can only be applied to methods not: ".concat(i(r)));var o=!1;return{configurable:!0,get(){if(o||this===t.prototype||this.hasOwnProperty(e)||"function"!=typeof r)return r;var s=r.bind(this);return o=!0,Object.defineProperty(this,e,{configurable:!0,get(){return s},set(t){r=t,delete this[e]}}),o=!1,s},set(t){r=t}}}function o(t){var e;return"undefined"!=typeof Reflect&&"function"==typeof Reflect.ownKeys?e=Reflect.ownKeys(t.prototype):(e=Object.getOwnPropertyNames(t.prototype),"function"==typeof Object.getOwnPropertySymbols&&(e=e.concat(Object.getOwnPropertySymbols(t.prototype)))),e.forEach((e=>{if("constructor"!==e){var s=Object.getOwnPropertyDescriptor(t.prototype,e);"function"==typeof s.value&&Object.defineProperty(t.prototype,e,r(t,e,s))}})),t}function n(){return 1===arguments.length?o.apply(void 0,arguments):r.apply(void 0,arguments)}s.d(e,{Ay(){return n}})},36115(t,e,s){"use strict";s.d(e,{T(){return r}});var i=s(17352);class r{constructor(){this.cache=!0,this.defaultTimeout=100,this.namespace="",this.safeMode=!1,this.width="auto",this.height="auto",this.safePluginsList=["about","enter","backspace","size","bold","hotkeys"],this.license="",this.preset="custom",this.presets={inline:{inline:!0,toolbar:!1,toolbarInline:!0,toolbarInlineForSelection:!0,showXPathInStatusbar:!1,showCharsCounter:!1,showWordsCounter:!1,showPlaceholder:!1}},this.ownerDocument="undefined"!=typeof document?document:null,this.ownerWindow="undefined"!=typeof window?window:null,this.shadowRoot=null,this.zIndex=0,this.readonly=!1,this.disabled=!1,this.activeButtonsInReadOnly=["source","fullsize","print","about","dots","selectall"],this.allowCommandsInReadOnly=["selectall","preview","print"],this.toolbarButtonSize="middle",this.allowTabNavigation=!1,this.inline=!1,this.theme="default",this.saveModeInStorage=!1,this.editorClassName=!1,this.className=!1,this.style=!1,this.containerStyle=!1,this.styleValues={},this.triggerChangeEvent=!0,this.direction="",this.language="auto",this.debugLanguage=!1,this.i18n=!1,this.tabIndex=-1,this.toolbar=!0,this.statusbar=!0,this.showTooltip=!0,this.showTooltipDelay=200,this.useNativeTooltip=!1,this.defaultActionOnPaste=i.INSERT_AS_HTML,this.enter=i.PARAGRAPH,this.iframe=!1,this.editHTMLDocumentMode=!1,this.enterBlock="br"!==this.enter?this.enter:i.PARAGRAPH,this.defaultMode=i.MODE_WYSIWYG,this.useSplitMode=!1,this.colors={greyscale:["#000000","#434343","#666666","#999999","#B7B7B7","#CCCCCC","#D9D9D9","#EFEFEF","#F3F3F3","#FFFFFF"],palette:["#980000","#FF0000","#FF9900","#FFFF00","#00F0F0","#00FFFF","#4A86E8","#0000FF","#9900FF","#FF00FF"],full:["#E6B8AF","#F4CCCC","#FCE5CD","#FFF2CC","#D9EAD3","#D0E0E3","#C9DAF8","#CFE2F3","#D9D2E9","#EAD1DC","#DD7E6B","#EA9999","#F9CB9C","#FFE599","#B6D7A8","#A2C4C9","#A4C2F4","#9FC5E8","#B4A7D6","#D5A6BD","#CC4125","#E06666","#F6B26B","#FFD966","#93C47D","#76A5AF","#6D9EEB","#6FA8DC","#8E7CC3","#C27BA0","#A61C00","#CC0000","#E69138","#F1C232","#6AA84F","#45818E","#3C78D8","#3D85C6","#674EA7","#A64D79","#85200C","#990000","#B45F06","#BF9000","#38761D","#134F5C","#1155CC","#0B5394","#351C75","#733554","#5B0F00","#660000","#783F04","#7F6000","#274E13","#0C343D","#1C4587","#073763","#20124D","#4C1130"]},this.colorPickerDefaultTab="background",this.imageDefaultWidth=300,this.removeButtons=[],this.disablePlugins=[],this.extraPlugins=[],this.extraButtons=[],this.extraIcons={},this.createAttributes={table:{style:"border-collapse:collapse;width: 100%;"}},this.sizeLG=900,this.sizeMD=700,this.sizeSM=400,this.buttons=[{group:"font-style",buttons:[]},{group:"list",buttons:[]},{group:"font",buttons:[]},"---",{group:"script",buttons:[]},{group:"media",buttons:[]},"\n",{group:"state",buttons:[]},{group:"clipboard",buttons:[]},{group:"insert",buttons:[]},{group:"indent",buttons:[]},{group:"color",buttons:[]},{group:"form",buttons:[]},"---",{group:"history",buttons:[]},{group:"search",buttons:[]},{group:"source",buttons:[]},{group:"other",buttons:[]},{group:"info",buttons:[]}],this.events={},this.textIcons=!1,this.showBrowserColorPicker=!0}static get defaultOptions(){return r.__defaultOptions||(r.__defaultOptions=new r),r.__defaultOptions}}r.prototype.controls={}},86302(t,e,s){"use strict";s.d(e,{j(){return h}});var i=s(17352),r=s(59146),o=s(69052),n=s(2461),a=s(25376),l=s(92039),c=s(98253),u=s(35642),d=(s(28712),s(21567));class h{constructor(){this.timers=new Map,this.__callbacks=new Map,this.__queueMicrotaskNative=queueMicrotask?.bind(window)??Promise.resolve().then.bind(Promise.resolve()),this.promisesRejections=new Set,this.requestsIdle=new Set,this.requestsRaf=new Set,this.requestIdleCallbackNative=window.requestIdleCallback?.bind(window)??((t,e)=>{const s=Date.now();return this.setTimeout((()=>{t({didTimeout:!1,timeRemaining(){return Math.max(0,50-(Date.now()-s))}})}),e?.timeout??1)}),this.__cancelIdleCallbackNative=window.cancelIdleCallback?.bind(window)??(t=>{this.clearTimeout(t)}),this.isDestructed=!1}delay(t){return this.promise((e=>this.setTimeout(e,t)))}setTimeout(t,e,...s){if(this.isDestructed)return 0;let i={};(0,u.R)(e)&&(e=0),(0,n.E)(e)||(i=e,e=i.timeout||0),i.label&&this.clearLabel(i.label);const o=(0,r.w)(t,e,...s),a=i.label||o;return this.timers.set(a,o),this.__callbacks.set(a,t),o}updateTimeout(t,e){if(!t||!this.timers.has(t))return null;const s=this.__callbacks.get(t);return this.setTimeout(s,{label:t,timeout:e})}clearLabel(t){t&&this.timers.has(t)&&((0,r.D)(this.timers.get(t)),this.timers.delete(t),this.__callbacks.delete(t))}clearTimeout(t){if((0,c.K)(t))return this.clearLabel(t);(0,r.D)(t),this.timers.delete(t),this.__callbacks.delete(t)}debounce(t,e,s=!1){let i=0,n=!1;const c=[],u=(...e)=>{if(!n){i=0;const s=t(...e);if(n=!0,c.length){const t=()=>{c.forEach((t=>t())),c.length=0};(0,l.y)(s)?s.finally(t):t()}}},d=(...a)=>{n=!1,e?(!i&&s&&u(...a),(0,r.D)(i),i=this.setTimeout((()=>u(...a)),(0,o.T)(e)?e():e),this.timers.set(t,i)):u(...a)};return(0,a.Q)(e)&&e.promisify?(...t)=>{const e=this.promise((t=>{c.push(t)}));return d(...t),e}:d}microDebounce(t,e=!1){let s,i=!1,r=!0;return(...o)=>{s=o,i?r=!0:(r=!0,e&&(r=!1,t(...s)),i=!0,this.__queueMicrotaskNative((()=>{i=!1,this.isDestructed||r&&t(...s)})))}}throttle(t,e,s=!1){let i,r,n,a=null;return(...s)=>{i=!0,n=s,e?a||(r=()=>{i?(t(...n),i=!1,a=this.setTimeout(r,(0,o.T)(e)?e():e),this.timers.set(r,a)):a=null},r()):t(...n)}}promise(t){let e=()=>{};const s=new Promise(((s,i)=>{e=()=>i((0,d.h)()),this.promisesRejections.add(e),t(s,i)}));return s.finally||"undefined"==typeof process||i.IS_ES_NEXT||(s.finally=t=>(s.then(t).catch(t),s)),s.finally((()=>{this.promisesRejections.delete(e)})).catch((()=>null)),s.rejectCallback=e,s}promiseState(t){if(t.status)return t.status;if(!Promise.race)return new Promise((e=>{t.then((t=>(e("fulfilled"),t)),(t=>{throw e("rejected"),t})),this.setTimeout((()=>{e("pending")}),100)}));const e={};return Promise.race([t,e]).then((t=>t===e?"pending":"fulfilled"),(()=>"rejected"))}requestIdleCallback(t,e){const s=this.requestIdleCallbackNative(t,e);return this.requestsIdle.add(s),s}requestIdlePromise(t){return this.promise((e=>{const s=this.requestIdleCallback((()=>e(s)),t)}))}cancelIdleCallback(t){return this.requestsIdle.delete(t),this.__cancelIdleCallbackNative(t)}requestAnimationFrame(t){const e=requestAnimationFrame(t);return this.requestsRaf.add(e),e}cancelAnimationFrame(t){this.requestsRaf.delete(t),cancelAnimationFrame(t)}clear(){this.requestsIdle.forEach((t=>this.cancelIdleCallback(t))),this.requestsRaf.forEach((t=>this.cancelAnimationFrame(t))),this.timers.forEach((t=>(0,r.D)(this.timers.get(t)))),this.timers.clear(),this.promisesRejections.forEach((t=>t())),this.promisesRejections.clear()}destruct(){this.clear(),this.isDestructed=!0}}},64890(t,e,s){"use strict";s.d(e,{j(){return i.j}});var i=s(86302)},37474(t,e,s){"use strict";s.d(e,{u(){return l}});var i=s(64890),r=s(64567),o=s(56298),n=s(65147);const a=new Map;class l{get componentName(){return this.__componentName||(this.__componentName="jodit-"+(0,n.kebabCase)(((0,n.isFunction)(this.className)?this.className():"")||(0,n.getClassName)(this))),this.__componentName}getFullElName(t,e,s){const i=[this.componentName];return t&&(t=t.replace(/[^a-z0-9-]/gi,"-"),i.push("__"+t)),e&&(i.push("_",e),i.push("_",(0,n.isVoid)(s)?"true":""+s)),i.join("")}get ownerDocument(){return this.ow.document}get od(){return this.ownerDocument}get ow(){return this.ownerWindow}get(t,e){return(0,n.get)(t,e||this)}get isReady(){return this.componentStatus===r.f.ready}get isDestructed(){return this.componentStatus===r.f.destructed}get isInDestruct(){return r.f.beforeDestruct===this.componentStatus||r.f.destructed===this.componentStatus}bindDestruct(t){return t.hookStatus(r.f.beforeDestruct,(()=>!this.isInDestruct&&this.destruct())),this}constructor(){this.async=new i.j,this.ownerWindow=window,this.__componentStatus=r.f.beforeInit,this.uid="jodit-uid-"+(0,o.w9)()}destruct(){this.setStatus(r.f.destructed),this.async&&(this.async.destruct(),this.async=void 0),a.get(this)&&a.delete(this),this.ownerWindow=void 0}get componentStatus(){return this.__componentStatus}set componentStatus(t){this.setStatus(t)}setStatus(t){return this.setStatusComponent(t,this)}setStatusComponent(t,e){if(t===this.__componentStatus)return;e===this&&(this.__componentStatus=t);const s=Object.getPrototypeOf(this);s&&(0,n.isFunction)(s.setStatusComponent)&&s.setStatusComponent(t,e);const i=a.get(this),r=i?.[t];r&&r.length&&r.forEach((t=>t(e)))}hookStatus(t,e){let s=a.get(this);s||(s={},a.set(this,s)),s[t]||(s[t]=[]),s[t].push(e)}static isInstanceOf(t,e){return t instanceof e}}l.STATUSES=r.f},77753(t,e,s){"use strict";s.d(e,{f(){return r.f},uA(){return i.u},vG(){return o.v}});var i=s(37474),r=s(64567),o=s(7982)},64567(t,e,s){"use strict";s.d(e,{f(){return i}});const i={beforeInit:"beforeInit",ready:"ready",beforeDestruct:"beforeDestruct",destructed:"destructed"}},7982(t,e,s){"use strict";s.d(e,{v(){return r}});var i=s(37474);class r extends i.u{get j(){return this.jodit}get defaultTimeout(){return this.j.defaultTimeout}i18n(t,...e){return this.j.i18n(t,...e)}setParentView(t){return this.jodit=t,t.components.add(this),this}constructor(t){super(),this.setParentView(t)}destruct(){return this.j.components.delete(this),super.destruct()}}},17352(t,e,s){"use strict";s.r(e),s.d(e,{ACCURACY(){return J},APP_VERSION(){return i},BASE_PATH(){return at},BR(){return F},CLIPBOARD_ID(){return ut},COMMAND_KEYS(){return H},EMULATE_DBLCLICK_TIMEOUT(){return Q},ES(){return r},FAT_MODE(){return c},HOMEPAGE(){return u},INSEPARABLE_TAGS(){return T},INSERT_AS_HTML(){return tt},INSERT_AS_TEXT(){return st},INSERT_CLEAR_HTML(){return et},INSERT_ONLY_TEXT(){return it},INVISIBLE_SPACE(){return p},INVISIBLE_SPACE_REG_EXP(){return g},INVISIBLE_SPACE_REG_EXP_END(){return f},INVISIBLE_SPACE_REG_EXP_START(){return v},IS_BLOCK(){return w},IS_ES_MODERN(){return o},IS_ES_NEXT(){return n},IS_IE(){return K},IS_INLINE(){return C},IS_MAC(){return ot},IS_PROD(){return a},IS_TEST(){return l},KEY_ALIASES(){return nt},KEY_ALT(){return A},KEY_BACKSPACE(){return I},KEY_DELETE(){return D},KEY_DOWN(){return N},KEY_ENTER(){return z},KEY_ESC(){return L},KEY_F3(){return q},KEY_LEFT(){return M},KEY_META(){return x},KEY_RIGHT(){return R},KEY_SPACE(){return B},KEY_TAB(){return j},KEY_UP(){return P},LIST_TAGS(){return k},MARKER_CLASS(){return Z},MODE_SOURCE(){return $},MODE_SPLIT(){return U},MODE_WYSIWYG(){return W},NBSP_SPACE(){return m},NEARBY(){return O},NO_EMPTY_TAGS(){return E},PARAGRAPH(){return V},PASSIVE_EVENTS(){return ht},SAFE_COUNT_CHANGE_CALL(){return rt},SET_TEST(){return d},SOURCE_CONSUMER(){return dt},SPACE_REG_EXP(){return b},SPACE_REG_EXP_END(){return _},SPACE_REG_EXP_START(){return y},TEMP_ATTR(){return lt},TEXT_HTML(){return G},TEXT_PLAIN(){return Y},TEXT_RTF(){return X},TOKENS(){return h},lang(){return ct}});const i="4.2.5",r="es2021",o=!0,n=!0,a=!0;let l=!1;const c=!1,u="https://xdsoft.net/jodit/",d=()=>l=!0,h={},p="\ufeff",m=" ",g=()=>/[\uFEFF]/g,f=()=>/[\uFEFF]+$/g,v=()=>/^[\uFEFF]+/g,b=()=>/[\s\n\t\r\uFEFF\u200b]+/g,y=()=>/^[\s\n\t\r\uFEFF\u200b]+/g,_=()=>/[\s\n\t\r\uFEFF\u200b]+$/g,w=/^(ADDRESS|ARTICLE|ASIDE|BLOCKQUOTE|CANVAS|DD|DFN|DIV|DL|DT|FIELDSET|FIGCAPTION|FIGURE|FOOTER|FORM|H[1-6]|HEADER|HGROUP|HR|LI|MAIN|NAV|NOSCRIPT|OUTPUT|P|PRE|RUBY|SCRIPT|STYLE|OBJECT|OL|SECTION|IFRAME|JODIT|JODIT-MEDIA|UL|TR|TD|TH|TBODY|THEAD|TFOOT|TABLE|BODY|HTML|VIDEO)$/i,C=/^(STRONG|SPAN|I|EM|B|SUP|SUB|A|U)$/i,k=new Set(["ul","ol"]),S=["img","video","svg","iframe","script","input","textarea","link","jodit","jodit-media"],T=new Set([...S,"br","hr"]),E=new Set(S),x="Meta",I="Backspace",j="Tab",z="Enter",L="Escape",A="Alt",M="ArrowLeft",P="ArrowUp",R="ArrowRight",N="ArrowDown",B="Space",D="Delete",q="F3",O=5,J=10,H=[x,I,D,P,N,R,M,z,L,q,j],F="br",V="p",W=1,$=2,U=3,K="undefined"!=typeof navigator&&(-1!==navigator.userAgent.indexOf("MSIE")||/rv:11.0/i.test(navigator.userAgent)),Y=K?"text":"text/plain",G=K?"html":"text/html",X=K?"rtf":"text/rtf",Z="jodit-selection_marker",Q=300,tt="insert_as_html",et="insert_clear_html",st="insert_as_text",it="insert_only_text",rt=10,ot="undefined"!=typeof window&&/Mac|iPod|iPhone|iPad/.test(window.navigator.platform),nt={add:"+",break:"pause",cmd:"meta",command:"meta",ctl:"control",ctrl:"control",del:"delete",down:"arrowdown",esc:"escape",ins:"insert",left:"arrowleft",mod:ot?"meta":"control",opt:"alt",option:"alt",return:"enter",right:"arrowright",space:" ",spacebar:" ",up:"arrowup",win:"meta",windows:"meta"},at=(()=>{if("undefined"==typeof document)return"";const t=document.currentScript,e=t=>{const e=t.split("/");return/\.js/.test(e[e.length-1])?e.slice(0,e.length-1).join("/")+"/":t};if(t)return e(t.src);const s=document.querySelectorAll("script[src]");return s&&s.length?e(s[s.length-1].src):window.location.href})(),lt="data-jodit-temp",ct={},ut="clipboard",dt="source-consumer",ht=new Set(["touchstart","touchend","scroll","mousewheel","mousemove","touchmove"])},92852(t,e,s){"use strict";s.d(e,{X(){return n}});var i=s(17352),r=s(55186),o=s(65147);s(28712);class n{get doc(){return(0,o.isFunction)(this.document)?this.document():this.document}constructor(t,e){this.document=t,this.createAttributes=e}element(t,e,s){const i=this.doc.createElement(t.toLowerCase());return this.applyCreateAttributes(i),e&&((0,o.isPlainObject)(e)?(0,o.attr)(i,e):s=e),s&&(0,o.asArray)(s).forEach((t=>i.appendChild((0,o.isString)(t)?this.fromHTML(t):t))),i}div(t,e,s){const i=this.element("div",e,s);return t&&(i.className=t),i}sandbox(){const t=this.element("iframe",{sandbox:"allow-same-origin"});this.doc.body.appendChild(t);const e=t.contentWindow?.document;if(!e)throw Error("Iframe error");return e.open(),e.write(""),e.close(),[e.body,t]}span(t,e,s){const i=this.element("span",e,s);return t&&(i.className=t),i}a(t,e,s){const i=this.element("a",e,s);return t&&(i.className=t),i}text(t){return this.doc.createTextNode(t)}fake(){return this.text(i.INVISIBLE_SPACE)}fragment(){return this.doc.createDocumentFragment()}fromHTML(t,e){const s=this.div();s.innerHTML=""+t;const i=s.firstChild===s.lastChild&&s.firstChild?s.firstChild:s;if(r.J.safeRemove(i),e){const t=(0,o.refs)(i);Object.keys(e).forEach((s=>{const i=t[s];i&&!1===e[s]&&r.J.hide(i)}))}return i}applyCreateAttributes(t){if(this.createAttributes){const e=this.createAttributes;if(e&&e[t.tagName.toLowerCase()]){const s=e[t.tagName.toLowerCase()];(0,o.isFunction)(s)?s(t):(0,o.isPlainObject)(s)&&(0,o.attr)(t,s)}}}}},40594(t,e,s){"use strict";s.d(e,{X(){return i.X}});var i=s(92852)},11961(t,e,s){"use strict";s.d(e,{d(){return i.Ay}});var i=s(26318)},87875(t,e,s){"use strict";s.d(e,{OK(){return c},PO(){return a},PP(){return l}});var i=s(64567),r=s(55186),o=s(9823),n=s(76166);function a(t,e){const s=Object.getOwnPropertyDescriptor(t,e);return!s||(0,o.Tn)(s.get)?null:s.value}function l(t,e,s){const i=s.get;if(!i)throw(0,n.z3)("Getter property descriptor expected");s.get=function(){const t=i.call(this);return t&&!0===t.noCache||Object.defineProperty(this,e,{configurable:s.configurable,enumerable:s.enumerable,writable:!1,value:t}),t}}function c(t,e,s){const a=s.value;if(!(0,o.Tn)(a))throw(0,n.z3)("Handler must be a Function");let l=!0;const c=new WeakMap;s.value=function(...t){if(l&&c.has(this.constructor))return c.get(this.constructor)?.cloneNode(!0);const e=a.apply(this,t);return l&&r.J.isElement(e)&&c.set(this.constructor,e),l?e.cloneNode(!0):e},t.hookStatus(i.f.ready,(t=>{const e=(0,o.hH)(t)?t:t.jodit;l=!!e.options.cache}))}},24767(t,e,s){"use strict";function i(t){class e extends t{constructor(...t){super(...t),this.constructor===e&&(this instanceof e||Object.setPrototypeOf(this,e.prototype),this.setStatus("ready"))}}return e}s.d(e,{s(){return i}})},37075(t,e,s){"use strict";s.d(e,{n(){return a},s(){return n}});var i=s(77753),r=s(9823),o=(s(28712),s(50156));function n(t,e=!1,s="debounce"){return(n,a)=>{const l=n[a];if(!(0,r.Tn)(l))throw(0,o.z3)("Handler must be a Function");return n.hookStatus(i.f.ready,(i=>{const{async:o}=i,n=(0,r.Tn)(t)?t(i):t,l=(0,r.Et)(n)||(0,r.Qd)(n)?n:i.defaultTimeout;Object.defineProperty(i,a,{configurable:!0,value:o[s](i[a].bind(i),l,e)})})),{configurable:!0,get(){return l.bind(this)}}}}function a(t,e=!1){return n(t,e,"throttle")}},1963(t,e,s){"use strict";s.d(e,{C(){return r}});var i=s(69052);function r(...t){return e=>{const s=e.prototype;for(let e=0;t.length>e;e++){const r=t[e],o=Object.getOwnPropertyNames(r.prototype);for(let t=0;o.length>t;t++){const e=o[t],n=Object.getOwnPropertyDescriptor(r.prototype,e);null!=n&&(0,i.T)(n.value)&&!(0,i.T)(s[e])&&Object.defineProperty(s,e,{enumerable:!0,configurable:!0,writable:!0,value(...t){return n.value.call(this,...t)}})}}}}},71151(t,e,s){"use strict";s.d(e,{A(){return o}});var i=s(69052),r=s(50156);function o(t){return(e,s)=>{if(!(0,i.T)(e[s]))throw(0,r.z3)("Handler must be a Function");e.hookStatus(t,(t=>{t[s].call(t)}))}}},86285(t,e,s){"use strict";s.d(e,{N(){return n}});var i=s(77753),r=s(69052),o=s(50156);function n(){return(t,e)=>{if(!(0,r.T)(t[e]))throw(0,o.z3)("Handler must be a Function");t.hookStatus(i.f.ready,(t=>{const{async:s}=t,i=t[e];t[e]=(...e)=>s.requestIdleCallback(i.bind(t,...e))}))}}},22664(t,e,s){"use strict";s.r(e),s.d(e,{autobind(){return i.d},cache(){return r.PP},cacheHTML(){return r.OK},cached(){return r.PO},component(){return o.s},debounce(){return n.s},derive(){return a.C},getPropertyDescriptor(){return p.N},hook(){return l.A},idle(){return c.N},nonenumerable(){return u.m},persistent(){return d.y},throttle(){return n.n},wait(){return h.u},watch(){return p.w}});var i=s(11961),r=s(87875),o=s(24767),n=s(37075),a=s(1963),l=s(71151),c=s(86285),u=s(48791),d=s(33087),h=s(48647),p=s(66927)},48791(t,e,s){"use strict";s.d(e,{m(){return i}});const i=(t,e)=>{!1!==(Object.getOwnPropertyDescriptor(t,e)||{}).enumerable&&Object.defineProperty(t,e,{enumerable:!1,set(t){Object.defineProperty(this,e,{enumerable:!1,writable:!0,value:t})}})}},33087(t,e,s){"use strict";s.d(e,{y(){return o}});var i=s(64567),r=s(12041);function o(t,e){t.hookStatus(i.f.ready,(t=>{const s=(0,r.h)(t)?t:t.jodit,i=`${s.options.namespace}${t.componentName}_prop_${e}`,o=t[e];Object.defineProperty(t,e,{get:()=>s.storage.get(i)??o,set(t){s.storage.set(i,t)}})}))}},48647(t,e,s){"use strict";s.d(e,{u(){return n}});var i=s(64567),r=s(69052),o=s(50156);function n(t){return(e,s)=>{if(!(0,r.T)(e[s]))throw(0,o.z3)("Handler must be a Function");e.hookStatus(i.f.ready,(e=>{const{async:i}=e,r=e[s];let o=0;Object.defineProperty(e,s,{configurable:!0,value:function s(...n){i.clearTimeout(o),t(e)?r.apply(e,n):o=i.setTimeout((()=>s(...n)),10)}})}))}}},66927(t,e,s){"use strict";s.d(e,{N(){return u},w(){return d}});var i=s(64567),r=s(32332),o=s(42589),n=s(69052),a=s(25376),l=s(12041),c=s(50156);function u(t,e){let s;do{s=Object.getOwnPropertyDescriptor(t,e),t=Object.getPrototypeOf(t)}while(!s&&t);return s}function d(t,e){return(s,d)=>{if(!(0,n.T)(s[d]))throw(0,c.z3)("Handler must be a Function");const h=e?.immediately??!0,p=e?.context,m=e=>{const i=(0,l.h)(e)?e:e.jodit;let c=(t,...s)=>{if(!e.isInDestruct)return e[d](t,...s)};h||(c=e.async.microDebounce(c,!0)),(0,o.u)(t).forEach((t=>{if(/:/.test(t)){const[s,r]=t.split(":");let o=p;return s.length&&(o=e.get(s)),(0,n.T)(o)&&(o=o(e)),i.events.on(o||e,r,c),o||i.events.on(r,c),void e.hookStatus("beforeDestruct",(()=>{i.events.off(o||e,r,c).off(r,c)}))}const o=t.split("."),[l]=o,d=o.slice(1);let h=e[l];(0,a.Q)(h)&&(0,r.s)(h).on("change."+d.join("."),c);const m=u(s,l);Object.defineProperty(e,l,{configurable:!0,set(t){const s=h;s!==t&&(h=t,m&&m.set&&m.set.call(e,t),(0,a.Q)(h)&&(h=(0,r.s)(h),h.on("change."+d.join("."),c)),c(l,s,h))},get:()=>m&&m.get?m.get.call(e):h})}))};(0,n.T)(s.hookStatus)?s.hookStatus(i.f.ready,m):m(s)}}},55186(t,e,s){"use strict";s.d(e,{J(){return l}});var i=s(17352),r=s(42448),o=s(9823),n=s(59101),a=s(97369);class l{constructor(){throw Error("Dom is static module")}static detach(t){for(;t&&t.firstChild;)t.removeChild(t.firstChild)}static wrapInline(t,e,s){let i,r=t,n=t;s.s.save();let a=!1;do{a=!1,i=r.previousSibling,i&&!l.isBlock(i)&&(a=!0,r=i)}while(a);do{a=!1,i=n.nextSibling,i&&!l.isBlock(i)&&(a=!0,n=i)}while(a);const c=(0,o.Kg)(e)?s.createInside.element(e):e;r.parentNode&&r.parentNode.insertBefore(c,r);let u=r;for(;u&&(u=r.nextSibling,c.appendChild(r),r!==n&&u);)r=u;return s.s.restore(),c}static wrap(t,e,s){const i=(0,o.Kg)(e)?s.element(e):e;if(l.isNode(t)){if(!t.parentNode)throw(0,a.error)("Element should be in DOM");t.parentNode.insertBefore(i,t),i.appendChild(t)}else{const e=t.extractContents();t.insertNode(i),i.appendChild(e)}return i}static unwrap(t){const e=t.parentNode;if(e){for(;t.firstChild;)e.insertBefore(t.firstChild,t);l.safeRemove(t)}}static between(t,e,s){let i=t;for(;i&&i!==e&&(t===i||!s(i));){let t=i.firstChild||i.nextSibling;if(!t){for(;i&&!i.nextSibling;)i=i.parentNode;t=i?.nextSibling}i=t}}static replace(t,e,s,i=!1,n=!1){(0,o.AH)(e)&&(e=s.fromHTML(e));const a=(0,o.Kg)(e)?s.element(e):e;if(!n)for(;t.firstChild;)a.appendChild(t.firstChild);return i&&l.isElement(t)&&l.isElement(a)&&(0,r.$)(t.attributes).forEach((t=>{a.setAttribute(t.name,t.value)})),t.parentNode&&t.parentNode.replaceChild(a,t),a}static isEmptyTextNode(t){return l.isText(t)&&(!t.nodeValue||0===t.nodeValue.replace(i.INVISIBLE_SPACE_REG_EXP(),"").trim().length)}static isEmptyContent(t){return l.each(t,(t=>l.isEmptyTextNode(t)))}static isContentEditable(t,e){return l.isNode(t)&&!l.closest(t,(t=>l.isElement(t)&&"false"===t.getAttribute("contenteditable")),e)}static isEmpty(t,e=i.NO_EMPTY_TAGS){if(!t)return!0;let s;s=(0,o.Tn)(e)?e:t=>e.has(t.nodeName.toLowerCase());const r=t=>null==t.nodeValue||0===(0,n.Bq)(t.nodeValue).length;return l.isText(t)?r(t):!(l.isElement(t)&&s(t))&&l.each(t,(t=>{if(l.isText(t)&&!r(t)||l.isElement(t)&&s(t))return!1}))}static isNode(t){return!!(t&&(0,o.Kg)(t.nodeName)&&"number"==typeof t.nodeType&&t.childNodes&&(0,o.Tn)(t.appendChild))}static isCell(t){return l.isNode(t)&&("TD"===t.nodeName||"TH"===t.nodeName)}static isList(t){return l.isTag(t,i.LIST_TAGS)}static isLeaf(t){return l.isTag(t,"li")}static isImage(t){return l.isNode(t)&&/^(img|svg|picture|canvas)$/i.test(t.nodeName)}static isBlock(t){return!(0,o.Rd)(t)&&"object"==typeof t&&l.isNode(t)&&i.IS_BLOCK.test(t.nodeName)}static isText(t){return!(!t||t.nodeType!==Node.TEXT_NODE)}static isComment(t){return!(!t||t.nodeType!==Node.COMMENT_NODE)}static isElement(t){if(!l.isNode(t))return!1;const e=t.ownerDocument?.defaultView;return!(!e||t.nodeType!==Node.ELEMENT_NODE)}static isFragment(t){if(!l.isNode(t))return!1;const e=t.ownerDocument?.defaultView;return!(!e||t.nodeType!==Node.DOCUMENT_FRAGMENT_NODE)}static isHTMLElement(t){if(!l.isNode(t))return!1;const e=t.ownerDocument?.defaultView;return!!(e&&t instanceof e.HTMLElement)}static isInlineBlock(t){return l.isElement(t)&&!/^(BR|HR)$/i.test(t.tagName)&&-1!==["inline","inline-block"].indexOf(""+(0,a.css)(t,"display"))}static canSplitBlock(t){return!(0,o.Rd)(t)&&l.isHTMLElement(t)&&l.isBlock(t)&&!/^(TD|TH|CAPTION|FORM)$/.test(t.nodeName)&&void 0!==t.style&&!/^(fixed|absolute)/i.test(t.style.position)}static last(t,e){let s=t?.lastChild;if(!s)return null;do{if(e(s))return s;let i=s.lastChild;if(i||(i=s.previousSibling),!i&&s.parentNode!==t){do{s=s.parentNode}while(s&&!s?.previousSibling&&s.parentNode!==t);i=s?.previousSibling}s=i}while(s);return null}static prev(t,e,s,i=!0){return l.find(t,e,s,!1,i)}static next(t,e,s,i=!0){return l.find(t,e,s,!0,i)}static prevWithClass(t,e){return l.prev(t,(t=>l.isElement(t)&&t.classList.contains(e)),t.parentNode)}static nextWithClass(t,e){return l.next(t,(t=>l.isElement(t)&&t.classList.contains(e)),t.parentNode)}static find(t,e,s,i=!0,r=!0){const o=this.nextGen(t,s,i,r);let n=o.next();for(;!n.done;){if(e(n.value))return n.value;n=o.next()}return null}static*nextGen(t,e,s=!0,i=!0){const r=[];let o=t;do{let e=s?o.nextSibling:o.previousSibling;for(;e;)r.unshift(e),e=s?e.nextSibling:e.previousSibling;yield*this.runInStack(t,r,s,i),o=o.parentNode}while(o&&o!==e);return null}static each(t,e,s=!0){const i=this.eachGen(t,s);let r=i.next();for(;!r.done;){if(!1===e(r.value))return!1;r=i.next()}return!0}static eachGen(t,e=!0){return this.runInStack(t,[t],e)}static*runInStack(t,e,s,i=!0){for(;e.length;){const r=e.pop();if(i){let t=s?r.lastChild:r.firstChild;for(;t;)e.push(t),t=s?t.previousSibling:t.nextSibling}t!==r&&(yield r)}}static findWithCurrent(t,e,s,i="nextSibling",r="firstChild"){let o=t;do{if(e(o))return o||null;if(r&&o&&o[r]){const t=l.findWithCurrent(o[r],e,o,i,r);if(t)return t}for(;o&&!o[i]&&o!==s;)o=o.parentNode;o&&o[i]&&o!==s&&(o=o[i])}while(o&&o!==s);return null}static findSibling(t,e=!0,s=(t=>!l.isEmptyTextNode(t))){let i=l.sibling(t,e);for(;i&&!s(i);)i=l.sibling(i,e);return i&&s(i)?i:null}static findNotEmptySibling(t,e){return l.findSibling(t,e,(t=>!l.isEmptyTextNode(t)&&!!(!l.isText(t)||t.nodeValue?.length&&(0,n.Bq)(t.nodeValue))))}static findNotEmptyNeighbor(t,e,s){return(0,a.call)(e?l.prev:l.next,t,(t=>!(!t||(l.isText(t)||l.isComment(t))&&!(0,n.Bq)(t?.nodeValue||"").length)),s)}static sibling(t,e){return e?t.previousSibling:t.nextSibling}static up(t,e,s,i=!1){let r=t;if(!r)return null;do{if(e(r))return r;if(r===s||!r.parentNode)break;r=r.parentNode}while(r&&r!==s);return r===s&&i&&e(r)?r:null}static closest(t,e,s){let i;const r=t=>t.toLowerCase();if((0,o.Tn)(e))i=e;else if((0,o.cy)(e)||(0,o.vM)(e)){const t=(0,o.vM)(e)?e:new Set(e.map(r));i=e=>!(!e||!t.has(r(e.nodeName)))}else i=t=>!(!t||r(e)!==r(t.nodeName));return l.up(t,i,s)}static furthest(t,e,s){let i=null,r=t?.parentElement;for(;r&&r!==s;)e(r)&&(i=r),r=r?.parentElement;return i}static appendChildFirst(t,e){const s=t.firstChild;s?s!==e&&t.insertBefore(e,s):t.appendChild(e)}static after(t,e){const{parentNode:s}=t;s&&(s.lastChild===t?s.appendChild(e):s.insertBefore(e,t.nextSibling))}static before(t,e){const{parentNode:s}=t;s&&s.insertBefore(e,t)}static prepend(t,e){t.insertBefore(e,t.firstChild)}static append(t,e){(0,o.cy)(e)?e.forEach((e=>{this.append(t,e)})):t.appendChild(e)}static moveContent(t,e,s=!1,i=(()=>!0)){const o=(t.ownerDocument||document).createDocumentFragment();(0,r.$)(t.childNodes).filter((t=>!!i(t)||(l.safeRemove(t),!1))).forEach((t=>{o.appendChild(t)})),s&&e.firstChild?e.insertBefore(o,e.firstChild):e.appendChild(o)}static isOrContains(t,e,s=!1){return t===e?!s:!!(e&&t&&this.up(e,(e=>e===t),t,!0))}static safeRemove(...t){t.forEach((t=>l.isNode(t)&&t.parentNode&&t.parentNode.removeChild(t)))}static safeInsertNode(t,e){t.collapsed||t.deleteContents();const s=l.isFragment(e)?e.lastChild:e;t.startContainer===t.endContainer&&t.collapsed&&l.isTag(t.startContainer,i.INSEPARABLE_TAGS)?l.after(t.startContainer,e):(t.insertNode(e),s&&t.setStartBefore(s)),t.collapse(!0),[e.nextSibling,e.previousSibling].forEach((t=>l.isText(t)&&!t.nodeValue&&l.safeRemove(t)))}static hide(t){t&&((0,a.dataBind)(t,"__old_display",t.style.display),t.style.display="none")}static show(t){if(!t)return;const e=(0,a.dataBind)(t,"__old_display");"none"===t.style.display&&(t.style.display=e||"")}static isTag(t,e){if(!this.isElement(t))return!1;const s=t.tagName.toLowerCase(),i=t.tagName.toUpperCase();if(e instanceof Set)return e.has(s)||e.has(i);if(Array.isArray(e))throw new TypeError("Dom.isTag does not support array");return s===e||i===e}static markTemporary(t,e){return e&&(0,a.attr)(t,e),(0,a.attr)(t,i.TEMP_ATTR,!0),t}static isTemporary(t){return!!l.isElement(t)&&((0,o.rg)(t)||"true"===(0,a.attr)(t,i.TEMP_ATTR))}static replaceTemporaryFromString(t){return t.replace(/<([a-z]+)[^>]+data-jodit-temp[^>]+>(.+?)<\/\1>/gi,"$2")}static temporaryList(t){return(0,a.$$)(`[${i.TEMP_ATTR}]`,t)}}},71842(t,e,s){"use strict";s.d(e,{J(){return i.J},p(){return r.p}});var i=s(55186),r=s(8453)},8453(t,e,s){"use strict";s.d(e,{p(){return a}});var i=s(31635),r=s(22664),o=s(55186),n=s(43431);class a extends n.h{setWork(t){return this.isWorked&&this.break(),this.workNodes=o.J.eachGen(t,!this.options.reverse),this.isFinished=!1,this.startIdleRequest(),this}constructor(t,e={}){super(),this.async=t,this.options=e,this.workNodes=null,this.hadAffect=!1,this.isWorked=!1,this.isFinished=!1,this.idleId=0}startIdleRequest(){this.idleId=this.async.requestIdleCallback(this.workPerform,{timeout:this.options.timeout??10})}break(t){this.isWorked&&(this.stop(),this.emit("break",t))}end(){this.isWorked&&(this.stop(),this.emit("end",this.hadAffect),this.hadAffect=!1)}stop(){this.isWorked=!1,this.isFinished=!0,this.workNodes=null,this.async.cancelIdleCallback(this.idleId)}destruct(){super.destruct(),this.stop()}workPerform(t){if(this.workNodes){this.isWorked=!0;let e=0;const s=this.options.timeoutChunkSize??50;for(;!this.isFinished&&(t.timeRemaining()>0||t.didTimeout&&s>=e);){const t=this.workNodes.next();if(e+=1,this.visitNode(t.value)&&(this.hadAffect=!0),t.done)return void this.end()}}else this.end();this.isFinished||this.startIdleRequest()}visitNode(t){return!(!t||void 0!==this.options.whatToShow&&t.nodeType!==this.options.whatToShow)&&(this.emit("visit",t)??!1)}}(0,i.Cg)([r.autobind],a.prototype,"workPerform",null)},50658(t,e,s){"use strict";s.d(e,{b(){return u}});var i=s(17352),r=s(42589),o=s(37923),n=s(69052),a=s(98253),l=s(50156),c=s(10004);class u{mute(t){return this.__mutedEvents.add(t??"*"),this}isMuted(t){return!(!t||!this.__mutedEvents.has(t))||this.__mutedEvents.has("*")}unmute(t){return this.__mutedEvents.delete(t??"*"),this}__eachEvent(t,e){(0,r.u)(t).map((t=>t.trim())).forEach((t=>{const s=t.split(".");e.call(this,s[0],s[1]||c.X)}))}__getStore(t){if(!t)throw(0,l.z3)("Need subject");if(void 0===t[this.__key]){const e=new c.d;Object.defineProperty(t,this.__key,{enumerable:!1,configurable:!0,writable:!0,value:e})}return t[this.__key]}__removeStoreFromSubject(t){void 0!==t[this.__key]&&Object.defineProperty(t,this.__key,{enumerable:!1,configurable:!0,writable:!0,value:void 0})}__triggerNativeEvent(t,e){const s=this.__doc.createEvent("HTMLEvents");(0,a.K)(e)?s.initEvent(e,!0,!0):(s.initEvent(e.type,e.bubbles,e.cancelable),["screenX","screenY","clientX","clientY","target","srcElement","currentTarget","timeStamp","which","keyCode"].forEach((t=>{Object.defineProperty(s,t,{value:e[t],enumerable:!0})})),Object.defineProperty(s,"originalEvent",{value:e,enumerable:!0})),t.dispatchEvent(s)}get current(){return this.currents[this.currents.length-1]}on(t,e,s,r){let c,u,h,p;if((0,a.K)(t)||(0,a.B)(t)?(c=this,u=t,h=e,p=s):(c=t,u=e,h=s,p=r),!(0,a.K)(u)&&!(0,a.B)(u)||0===u.length)throw(0,l.z3)("Need events names");if(!(0,n.T)(h))throw(0,l.z3)("Need event handler");if((0,o.c)(c))return c.forEach((t=>{this.on(t,u,h,p)})),this;const m=c,g=this.__getStore(m),f=this;let v=function(t,...e){if(!f.isMuted(t))return h&&h.call(this,...e)};return d(m)&&(v=function(t){if(!f.isMuted(t.type))return f.__prepareEvent(t),h&&!1===h.call(this,t)?(t.preventDefault(),t.stopImmediatePropagation(),!1):void 0}),this.__eachEvent(u,((t,e)=>{if(0===t.length)throw(0,l.z3)("Need event name");if(!1===g.indexOf(t,e,h)&&(g.set(t,e,{event:t,originalCallback:h,syntheticCallback:v},p?.top),d(m))){const e=i.PASSIVE_EVENTS.has(t)?{passive:!0,capture:p?.capture??!1}:p?.capture??!1;v.options=e,m.addEventListener(t,v,e),this.__memoryDOMSubjectToHandler(m,v)}})),this}__memoryDOMSubjectToHandler(t,e){const s=this.__domEventsMap.get(t)||new Set;s.add(e),this.__domEventsMap.set(t,s)}__unmemoryDOMSubjectToHandler(t,e){const s=this.__domEventsMap,i=s.get(t)||new Set;i.delete(e),i.size?s.set(t,i):s.delete(t)}one(t,e,s,i){let r,o,n,l;(0,a.K)(t)||(0,a.B)(t)?(r=this,o=t,n=e,l=s):(r=t,o=e,n=s,l=i);const c=(...t)=>(this.off(r,o,c),n(...t));return this.on(r,o,c,l),this}off(t,e,s){let i,r,l;if((0,a.K)(t)||(0,a.B)(t)?(i=this,r=t,l=e):(i=t,r=e,l=s),(0,o.c)(i))return i.forEach((t=>{this.off(t,r,l)})),this;const u=i,h=this.__getStore(u);if(!(0,a.K)(r)&&!(0,a.B)(r)||0===r.length)return h.namespaces().forEach((t=>{this.off(u,"."+t)})),this.__removeStoreFromSubject(u),this;const p=t=>{d(u)&&(u.removeEventListener(t.event,t.syntheticCallback,t.syntheticCallback.options??!1),this.__unmemoryDOMSubjectToHandler(u,t.syntheticCallback))},m=(t,e)=>{if(""===t)return void h.events(e).forEach((t=>{""!==t&&m(t,e)}));const s=h.get(t,e);if(s&&s.length)if((0,n.T)(l)){const i=h.indexOf(t,e,l);!1!==i&&(p(s[i]),s.splice(i,1),s.length||h.clearEvents(e,t))}else s.forEach(p),s.length=0,h.clearEvents(e,t)};return this.__eachEvent(r,((t,e)=>{e===c.X?h.namespaces().forEach((e=>{m(t,e)})):m(t,e)})),h.isEmpty()&&this.__removeStoreFromSubject(u),this}stopPropagation(t,e){const s=(0,a.K)(t)?this:t,i=(0,a.K)(t)?t:e;if("string"!=typeof i)throw(0,l.z3)("Need event names");const r=this.__getStore(s);this.__eachEvent(i,((t,e)=>{const i=r.get(t,e);i&&this.__stopped.push(i),e===c.X&&r.namespaces(!0).forEach((e=>this.stopPropagation(s,t+"."+e)))}))}__removeStop(t){if(t){const e=this.__stopped.indexOf(t);-1!==e&&this.__stopped.splice(0,e+1)}}__isStopped(t){return void 0!==t&&-1!==this.__stopped.indexOf(t)}fire(t,e,...s){let i,r;const o=(0,a.K)(t)?this:t,n=(0,a.K)(t)?t:e,u=(0,a.K)(t)?[e,...s]:s;if(!d(o)&&!(0,a.K)(n))throw(0,l.z3)("Need events names");const h=this.__getStore(o);return!(0,a.K)(n)&&d(o)?this.__triggerNativeEvent(o,e):this.__eachEvent(n,((t,e)=>{if(d(o))this.__triggerNativeEvent(o,t);else{const s=h.get(t,e);if(s)try{[...s].every((e=>!this.__isStopped(s)&&(this.currents.push(t),r=e.syntheticCallback.call(o,t,...u),this.currents.pop(),void 0!==r&&(i=r),!0)))}finally{this.__removeStop(s)}e!==c.X||d(o)||h.namespaces().filter((t=>t!==e)).forEach((e=>{const s=this.fire.call(this,o,t+"."+e,...u);void 0!==s&&(i=s)}))}})),i}constructor(t){this.__domEventsMap=new Map,this.__mutedEvents=new Set,this.__key="__JoditEventEmitterNamespaces",this.__doc=document,this.__prepareEvent=t=>{t.cancelBubble||(t.composed&&(0,n.T)(t.composedPath)&&t.composedPath()[0]&&Object.defineProperty(t,"target",{value:t.composedPath()[0],configurable:!0,enumerable:!0}),t.type.match(/^touch/)&&t.changedTouches&&t.changedTouches.length&&["clientX","clientY","pageX","pageY"].forEach((e=>{Object.defineProperty(t,e,{value:t.changedTouches[0][e],configurable:!0,enumerable:!0})})),t.originalEvent||(t.originalEvent=t),"paste"===t.type&&void 0===t.clipboardData&&this.__doc.defaultView.clipboardData&&Object.defineProperty(t,"clipboardData",{get:()=>this.__doc.defaultView.clipboardData,configurable:!0,enumerable:!0}))},this.currents=[],this.__stopped=[],this.__isDestructed=!1,t&&(this.__doc=t),this.__key+=(new Date).getTime()}destruct(){this.__isDestructed||(this.__isDestructed=!0,this.__domEventsMap.forEach(((t,e)=>{this.off(e)})),this.__domEventsMap.clear(),this.__mutedEvents.clear(),this.currents.length=0,this.__stopped.length=0,this.off(this),this.__getStore(this).clear(),this.__removeStoreFromSubject(this))}}function d(t){return(0,n.T)(t.addEventListener)}},43431(t,e,s){"use strict";s.d(e,{h(){return i}});class i{constructor(){this.__map=new Map}on(t,e){return this.__map.has(t)||this.__map.set(t,new Set),this.__map.get(t)?.add(e),this}off(t,e){return this.__map.has(t)&&this.__map.get(t)?.delete(e),this}destruct(){this.__map.clear()}emit(t,...e){let s;return this.__map.has(t)&&this.__map.get(t)?.forEach((t=>{s=t(...e)})),s}}},50025(t,e,s){"use strict";s.d(e,{Xr(){return n.X},bk(){return i.b},d$(){return n.d},h5(){return r.h},sH(){return o.s}});var i=s(50658),r=s(43431),o=s(32332),n=s(10004)},32332(t,e,s){"use strict";s.d(e,{s(){return c}});var i=s(66927),r=s(37923),o=s(69810),n=s(25376);const a=Symbol("observable-object");function l(t){return void 0!==t[a]}function c(t){if(l(t))return t;const e={},s={},c=(e,i)=>(0,r.c)(e)?(e.map((t=>c(t,i))),t):(s[e]||(s[e]=[]),s[e].push(i),t),u=(i,...o)=>{if((0,r.c)(i))i.map((t=>u(t,...o)));else try{!e[i]&&s[i]&&(e[i]=!0,s[i].forEach((e=>e.call(t,...o))))}finally{e[i]=!1}},d=(e,s=[])=>{const r={};l(e)||(Object.defineProperty(e,a,{enumerable:!1,value:!0}),Object.keys(e).forEach((a=>{const l=a,c=s.concat(l).filter((t=>t.length));r[l]=e[l];const h=(0,i.N)(e,l);Object.defineProperty(e,l,{set(e){const s=r[l];if(!(0,o.P)(r[l],e)){u(["beforeChange","beforeChange."+c.join(".")],l,e),(0,n.Q)(e)&&d(e,c),h&&h.set?h.set.call(t,e):r[l]=e;const i=[];u(["change",...c.reduce(((t,e)=>(i.push(e),t.push("change."+i.join(".")),t)),[])],c.join("."),s,e?.valueOf?e.valueOf():e)}},get(){return h&&h.get?h.get.call(t):r[l]},enumerable:!0,configurable:!0}),(0,n.Q)(r[l])&&d(r[l],c)})),Object.defineProperty(t,"on",{value:c}))};return d(t),t}},10004(t,e,s){"use strict";s.d(e,{X(){return r},d(){return o}});var i=s(42448);s(28712);const r="JoditEventDefaultNamespace";class o{constructor(){this.__store=new Map}get(t,e){if(this.__store.has(e))return this.__store.get(e)[t]}indexOf(t,e,s){const i=this.get(t,e);if(i)for(let t=0;i.length>t;t+=1)if(i[t].originalCallback===s)return t;return!1}namespaces(t=!1){const e=(0,i.$)(this.__store.keys());return t?e.filter((t=>t!==r)):e}events(t){const e=this.__store.get(t);return e?Object.keys(e):[]}set(t,e,s,i=!1){let r=this.__store.get(e);r||(r={},this.__store.set(e,r)),void 0===r[t]&&(r[t]=[]),i?r[t].unshift(s):r[t].push(s)}clear(){this.__store.clear()}clearEvents(t,e){const s=this.__store.get(t);s&&s[e]&&(delete s[e],Object.keys(s).length||this.__store.delete(t))}isEmpty(){return 0===this.__store.size}}},56298(t,e,s){"use strict";s.d(e,{JW(){return b},My(){return _},RR(){return w},VF(){return h},av(){return v},fg(){return f},w9(){return g}});var i=s(83044),r=s(98253),o=s(12041),n=s(449),a=s(75766),l=s(77402),c=s(17352),u=s(71842),d=s(50025);const h={};let p=1;const m=new Set;function g(){function t(){return p+=10*(Math.random()+1),Math.round(p).toString(16)}let e=t();for(;m.has(e);)e=t();return m.add(e),e}const f=new l.$,v={},b=t=>{Object.keys(t).forEach((e=>{c.lang[e]?Object.assign(c.lang[e],t[e]):c.lang[e]=t[e]}))},y=new WeakMap;function _(t,e,s="div",l=!1){const c=(0,r.K)(e)?e:e?(0,a.u)(e.prototype):"jodit-utils",d=y.get(t)||{},h=c+s,p=(0,o.h)(t)?t:t.j;if(!d[h]){let e=p.c,r=(0,i.y)(t)&&t.o.shadowRoot?t.o.shadowRoot:t.od.body;if(l&&(0,i.y)(t)&&t.od!==t.ed){e=t.createInside;const o="style"===s?t.ed.head:t.ed.body;r=(0,i.y)(t)&&t.o.shadowRoot?t.o.shadowRoot:o}const o=e.element(s,{className:`jodit jodit-${(0,n.k)(c)}-container jodit-box`});o.classList.add("jodit_theme_"+(p.o.theme||"default")),r.appendChild(o),d[h]=o,t.hookStatus("beforeDestruct",(()=>{u.J.safeRemove(o),delete d[h],Object.keys(d).length&&y.delete(t)})),y.set(t,d)}return d[h].classList.remove("jodit_theme_default","jodit_theme_dark"),d[h].classList.add("jodit_theme_"+(p.o.theme||"default")),d[h]}const w=new d.bk},82317(t,e,s){"use strict";s.d(e,{_(){return r}});var i=s(37923);const r=t=>(0,i.c)(t)?t:[t]},32709(t,e,s){"use strict";s.d(e,{$r(){return o.$},_j(){return i._},uM(){return r.u}});var i=s(82317),r=s(42589),o=s(42448)},42589(t,e,s){"use strict";function i(t){return Array.isArray(t)?t:t.split(/[,\s]+/)}s.d(e,{u(){return i}})},42448(t,e,s){"use strict";s.d(e,{$(){return o}});var i=s(34796),r=s(44210);const o=(...t)=>((0,i.a)(Array.from)?Array.from:(0,r.c)("Array.from")??Array.from).apply(Array,t)},89044(t,e,s){"use strict";s.d(e,{D(){return i.D},w(){return i.w}});var i=s(59146)},59146(t,e,s){"use strict";function i(t,e,...s){return e?window.setTimeout(t,e,...s):(t.call(null,...s),0)}function r(t){window.clearTimeout(t)}s.d(e,{D(){return r},w(){return i}})},78479(t,e,s){"use strict";function i(){let t=!0;try{const e=document.createElement("input");e.type="color",e.value="!",t="color"===e.type&&"!"!==e.value}catch(e){t=!1}return t}s.d(e,{k(){return i}})},9823(t,e,s){"use strict";s.d(e,{AH(){return c.A},Bo(){return C.B},CE(){return u.C},E6(){return h.E},Et(){return v.E},Gp(){return d.n4},Kg(){return C.K},Lm(){return n.L},Mj(){return m.M},P5(){return a.P},Qd(){return y.Q},Rd(){return E.R},Tn(){return l.T},a3(){return f.a},cy(){return o.c},hH(){return T.h},kC(){return i.k},kO(){return d.kO},kf(){return b.k},l6(){return x.l},mv(){return k.m},n4(){return a.n},pV(){return d.pV},rg(){return g.r},uV(){return S.u},vM(){return w.v},y0(){return p.y},yL(){return _.y},zf(){return r.z}});var i=s(78479),r=s(99951),o=s(37923),n=s(9810),a=s(69810),l=s(69052),c=s(53701),u=s(21811),d=s(10058),h=s(3947),p=s(83044),m=s(82201),g=s(71274),f=s(34796),v=s(2461),b=s(12461),y=s(25376),_=s(92039),w=s(53470),C=s(98253),k=s(6939),S=s(59082),T=s(12041),E=s(35642),x=s(76776)},99951(t,e,s){"use strict";function i(t){return!!t&&t instanceof DOMException&&"AbortError"===t.name}s.d(e,{z(){return i}})},37923(t,e,s){"use strict";function i(t){return Array.isArray(t)}s.d(e,{c(){return i}})},9810(t,e,s){"use strict";function i(t){return"boolean"==typeof t}s.d(e,{L(){return i}})},69810(t,e,s){"use strict";s.d(e,{P(){return o},n(){return r}});var i=s(28616);function r(t,e){return t===e||(0,i.A)(t)===(0,i.A)(e)}function o(t,e){return t===e}},69052(t,e,s){"use strict";function i(t){return"function"==typeof t}s.d(e,{T(){return i}})},21811(t,e,s){"use strict";function i(t){return-1!==t.search(//)||-1!==t.search(//)||-1!==t.search(/style="[^"]*mso-/)&&-1!==t.search(/(0,i.K)(t)&&/<([A-Za-z][A-Za-z0-9]*)\b[^>]*>(.*?)<\/\1>/m.test(t.replace(/[\r\n]/g,""))},10058(t,e,s){"use strict";s.d(e,{kO(){return l},n4(){return n},pV(){return a}});var i=s(55186),r=s(69052),o=s(35642);function n(t){return!(0,o.R)(t)&&(0,r.T)(t.init)}function a(t){return!(0,o.R)(t)&&(0,r.T)(t.destruct)}function l(t){return!(0,o.R)(t)&&i.J.isElement(t.container)}},3947(t,e,s){"use strict";s.d(e,{E(){return o}});var i=s(12461),r=s(98253);function o(t){return(0,r.K)(t)&&(0,i.k)(t)&&(t=parseFloat(t)),"number"==typeof t&&Number.isFinite(t)&&!(t%1)}},83044(t,e,s){"use strict";s.d(e,{y(){return r}});var i=s(69052);function r(t){return!!(t&&t instanceof Object&&(0,i.T)(t.constructor)&&("undefined"!=typeof Jodit&&t instanceof Jodit||t.isJodit))}},82201(t,e,s){"use strict";s.d(e,{M(){return r}});var i=s(98253);const r=t=>(0,i.K)(t)&&23===t.length&&/^[a-z0-9]{5}-[a-z0-9]{5}-[a-z0-9]{5}-[a-z0-9]{5}$/i.test(t)},71274(t,e,s){"use strict";s.d(e,{r(){return o}});var i=s(17352),r=s(55186);function o(t){return r.J.isNode(t)&&r.J.isTag(t,"span")&&t.hasAttribute("data-"+i.MARKER_CLASS)}},34796(t,e,s){"use strict";function i(t){return!!t&&"function"===(typeof t).toLowerCase()&&(t===Function.prototype||/^\s*function\s*(\b[a-z$_][a-z0-9$_]*\b)*\s*\((|([a-z$_][a-z0-9$_]*)(\s*,[a-z$_][a-z0-9$_]*)*)\)\s*{\s*\[native code]\s*}\s*$/i.test(t+""))}s.d(e,{a(){return i}})},2461(t,e,s){"use strict";function i(t){return"number"==typeof t&&!isNaN(t)&&isFinite(t)}s.d(e,{E(){return i}})},12461(t,e,s){"use strict";s.d(e,{k(){return r}});var i=s(98253);function r(t){if((0,i.K)(t)){if(!t.match(/^([+-])?[0-9]+(\.?)([0-9]+)?(e[0-9]+)?$/))return!1;t=parseFloat(t)}return"number"==typeof t&&!isNaN(t)&&isFinite(t)}},25376(t,e,s){"use strict";s.d(e,{Q(){return r}});var i=s(76776);function r(t){return!(!t||"object"!=typeof t||t.nodeType||(0,i.l)(t)||t.constructor&&!{}.hasOwnProperty.call(t.constructor.prototype,"isPrototypeOf"))}},92039(t,e,s){"use strict";function i(t){return t&&"function"==typeof t.then}s.d(e,{y(){return i}})},53470(t,e,s){"use strict";s.d(e,{v(){return r}});var i=s(69052);function r(t){return!!t&&(0,i.T)(t.has)&&(0,i.T)(t.add)&&(0,i.T)(t.delete)}},98253(t,e,s){"use strict";s.d(e,{B(){return o},K(){return r}});var i=s(37923);function r(t){return"string"==typeof t}function o(t){return(0,i.c)(t)&&r(t[0])}},6939(t,e,s){"use strict";function i(t){if(t.includes(" "))return!1;if("undefined"!=typeof URL)try{const e=new URL(t);return["https:","http:","ftp:","file:","rtmp:"].includes(e.protocol)}catch(t){return!1}const e=document.createElement("a");return e.href=t,!!e.hostname}s.d(e,{m(){return i}})},59082(t,e,s){"use strict";function i(t){return!!t.length&&!/[^0-9A-Za-zа-яА-ЯЁё\w\-_. ]/.test(t)&&t.trim().length>0}s.d(e,{u(){return i}})},12041(t,e,s){"use strict";s.d(e,{h(){return r}});var i=s(69052);function r(t){return!!(t&&t instanceof Object&&(0,i.T)(t.constructor)&&t.isView)}},35642(t,e,s){"use strict";function i(t){return null==t}s.d(e,{R(){return i}})},76776(t,e,s){"use strict";function i(t){return null!=t&&t===t.window}s.d(e,{l(){return i}})},96768(t,e,s){"use strict";s.d(e,{s(){return i}});const i=t=>{if("rgba(0, 0, 0, 0)"===t||""===t)return!1;if(!t)return"#000000";if("#"===t.substr(0,1))return t;const e=/([\s\n\t\r]*?)rgb\((\d+), (\d+), (\d+)\)/.exec(t)||/([\s\n\t\r]*?)rgba\((\d+), (\d+), (\d+), ([\d.]+)\)/.exec(t);if(!e)return"#000000";const s=parseInt(e[2],10),i=parseInt(e[3],10);let r=(parseInt(e[4],10)|i<<8|s<<16).toString(16).toUpperCase();for(;6>r.length;)r="0"+r;return e[1]+"#"+r}},93495(t,e,s){"use strict";s.d(e,{s(){return i.s}});var i=s(96768)},56176(t,e,s){"use strict";s.d(e,{Z(){return l}});var i=s(17352),r=s(55186),o=s(59101),n=s(58720);function a(t){return t.replace(/mso-[a-z-]+:[\s]*[^;]+;/gi,"").replace(/mso-[a-z-]+:[\s]*[^";']+$/gi,"").replace(/border[a-z-]*:[\s]*[^;]+;/gi,"").replace(/([0-9.]+)(pt|cm)/gi,((t,e,s)=>{switch(s.toLowerCase()){case"pt":return(1.328*parseFloat(e)).toFixed(0)+"px";case"cm":return(.02645833*parseFloat(e)).toFixed(0)+"px"}return t}))}function l(t){if(-1===t.indexOf("")+7);const e=document.createElement("iframe");e.style.display="none",document.body.appendChild(e);let s="",l=[];try{const c=e.contentDocument||(e.contentWindow?e.contentWindow.document:null);if(c){c.open(),c.write(t),c.close();try{for(let t=0;c.styleSheets.length>t;t+=1){const e=c.styleSheets[t].cssRules;for(let t=0;e.length>t;t+=1)""!==e[t].selectorText&&(l=(0,n.$$)(e[t].selectorText,c.body),l.forEach((s=>{s.style.cssText=a(e[t].style.cssText+";"+s.style.cssText)})))}}catch(t){if(!i.IS_PROD)throw t}r.J.each(c.body,(t=>{if(r.J.isElement(t)){const e=t,s=e.getAttribute("style");s&&(e.style.cssText=a(s)),e.hasAttribute("style")&&!e.getAttribute("style")&&e.removeAttribute("style")}})),s=c.firstChild?(0,o.Bq)(c.body.innerHTML):""}}catch{}finally{r.J.safeRemove(e)}return s&&(t=s),(0,o.Bq)(t.replace(/<(\/)?(html|colgroup|col|o:p)[^>]*>/g,"").replace(//i);-1!==e&&(t=t.substring(e+20));const s=t.search(//i);return-1!==s&&(t=t.substring(0,s)),t})(s)),e.s.insertHTML(s)}function l(t){const e=t.types;let s="";if((0,o.cy)(e)||"[object DOMStringList]"==={}.toString.call(e))for(let t=0;e.length>t;t+=1)s+=e[t]+";";else s=(e||i.TEXT_PLAIN)+";";return s}function c(t,e,s,i,r){if(!1===t.e.fire("beforeOpenPasteDialog",e,s,i,r))return;const o=t.confirm(`
${t.i18n(e)}
`,t.i18n(s)),a=r.map((({text:e,value:s})=>(0,n.$n)(t,{text:e,name:e.toLowerCase(),tabIndex:0}).onAction((()=>{o.close(),i(s)}))));o.e.one(o,"afterClose",(()=>{t.s.isFocused()||t.s.focus()}));const l=(0,n.$n)(t,{text:"Cancel",tabIndex:0}).onAction((()=>{o.close()}));return o.setFooter([...a,l]),a[0].focus(),a[0].state.variant="primary",t.e.fire("afterOpenPasteDialog",o,e,s,i,r),o}},13861(t,e,s){"use strict";var i=s(31635),r=s(17352),o=s(22664),n=s(55186),a=s(56298),l=s(65147),c=s(29866),u=(s(70674),s(90823));class d extends c.k{constructor(){super(...arguments),this.pasteStack=new l.LimitedStack(20),this._isDialogOpened=!1}afterInit(t){t.e.on("paste.paste",this.onPaste).on("pasteStack.paste",(t=>this.pasteStack.push(t))),t.o.nl2brInPlainText&&this.j.e.on("processPaste.paste",this.onProcessPasteReplaceNl2Br)}beforeDestruct(t){t.e.off("paste.paste",this.onPaste).off("processPaste.paste",this.onProcessPasteReplaceNl2Br).off(".paste")}onPaste(t){try{if(!1===this.customPasteProcess(t)||!1===this.j.e.fire("beforePaste",t))return t.preventDefault(),!1;this.defaultPasteProcess(t)}finally{this.j.e.fire("afterPaste",t)}}customPasteProcess(t){if(!this.j.o.processPasteHTML)return;const e=(0,l.getDataTransfer)(t),s=[e?.getData(r.TEXT_PLAIN),e?.getData(r.TEXT_HTML),e?.getData(r.TEXT_RTF)];for(const e of s)if((0,l.isHTML)(e)&&(this.j.e.fire("processHTML",t,e,{plain:s[0],html:s[1],rtf:s[2]})||this.processHTML(t,e)))return!1}defaultPasteProcess(t){const e=(0,l.getDataTransfer)(t);let s=e?.getData(r.TEXT_HTML)||e?.getData(r.TEXT_PLAIN);if(e&&s&&""!==(0,l.trim)(s)){const i=this.j.e.fire("processPaste",t,s,(0,u.DI)(e));void 0!==i&&(s=i),((0,l.isString)(s)||n.J.isNode(s))&&this.__insertByType(t,s,this.j.o.defaultActionOnPaste),t.preventDefault(),t.stopPropagation()}}processHTML(t,e){if(!this.j.o.askBeforePasteHTML)return!1;if(this.j.o.memorizeChoiceWhenPasteFragment){const s=this.pasteStack.find((t=>t.html===e));if(s)return this.__insertByType(t,e,s.action||this.j.o.defaultActionOnPaste),!0}if(this._isDialogOpened)return!0;const s=(0,u.PU)(this.j,"Your code is similar to HTML. Keep as HTML?","Paste as HTML",(s=>{this._isDialogOpened=!1,this.__insertByType(t,e,s)}),this.j.o.pasteHTMLActionList);return s&&(this._isDialogOpened=!0,s.e.on("beforeClose",(()=>{this._isDialogOpened=!1}))),!0}__insertByType(t,e,s){if(this.pasteStack.push({html:e,action:s}),(0,l.isString)(e))switch(this.j.buffer.set(r.CLIPBOARD_ID,e),s){case r.INSERT_CLEAR_HTML:e=(0,l.cleanFromWord)(e);break;case r.INSERT_ONLY_TEXT:e=(0,l.stripTags)(e,this.j.ed,new Set(this.j.o.pasteExcludeStripTags));break;case r.INSERT_AS_TEXT:e=(0,l.htmlspecialchars)(e)}(0,u.sX)(t,this.j,e)}onProcessPasteReplaceNl2Br(t,e,s){if(s===r.TEXT_PLAIN+";"&&!(0,l.isHTML)(e))return(0,l.nl2br)(e)}}(0,i.Cg)([o.autobind],d.prototype,"onPaste",null),(0,i.Cg)([o.autobind],d.prototype,"onProcessPasteReplaceNl2Br",null),a.fg.add("paste",d)},50248(t,e,s){"use strict";var i=s(36115);i.T.prototype.showPlaceholder=!0,i.T.prototype.placeholder="Type something",i.T.prototype.useInputsPlaceholder=!0},225(t,e,s){"use strict";var i=s(31635),r=s(17352),o=s(22664),n=s(55186),a=s(56298),l=s(71274),c=s(26150),u=s(38322),d=s(29866);s(50248);class h extends d.k{constructor(){super(...arguments),this.addNativeListeners=()=>{this.j.e.off(this.j.editor,"input.placeholder keydown.placeholder").on(this.j.editor,"input.placeholder keydown.placeholder",this.toggle)},this.addEvents=()=>{const t=this.j;t.o.useInputsPlaceholder&&t.element.hasAttribute("placeholder")&&(this.placeholderElm.innerHTML=(0,c.C)(t.element,"placeholder")||""),t.e.fire("placeholder",this.placeholderElm.innerHTML),t.e.off(".placeholder").on("changePlace.placeholder",this.addNativeListeners).on("change.placeholder focus.placeholder keyup.placeholder mouseup.placeholder keydown.placeholder mousedown.placeholder afterSetMode.placeholder changePlace.placeholder",this.toggle).on(window,"load",this.toggle),this.addNativeListeners(),this.toggle()}}afterInit(t){t.o.showPlaceholder&&(this.placeholderElm=t.c.fromHTML(``),"rtl"===t.o.direction&&(this.placeholderElm.style.right="0px",this.placeholderElm.style.direction="rtl"),t.e.on("readonly",(t=>{t?this.hide():this.toggle()})).on("changePlace",this.addEvents),this.addEvents())}show(){const t=this.j;if(t.o.readonly)return;let e=0,s=0;const i=t.s.current(),r=i&&n.J.closest(i,n.J.isBlock,t.editor)||t.editor,o=t.ew.getComputedStyle(r),a=t.ew.getComputedStyle(t.editor);t.workplace.appendChild(this.placeholderElm);const{firstChild:c}=t.editor;if(n.J.isElement(c)&&!(0,l.r)(c)){const i=t.ew.getComputedStyle(c);e=parseInt(i.getPropertyValue("margin-top"),10),s=parseInt(i.getPropertyValue("margin-left"),10),this.placeholderElm.style.fontSize=parseInt(i.getPropertyValue("font-size"),10)+"px",this.placeholderElm.style.lineHeight=i.getPropertyValue("line-height")}else this.placeholderElm.style.fontSize=parseInt(o.getPropertyValue("font-size"),10)+"px",this.placeholderElm.style.lineHeight=o.getPropertyValue("line-height");(0,u.A)(this.placeholderElm,{display:"block",textAlign:o.getPropertyValue("text-align"),paddingTop:parseInt(a.paddingTop,10)+"px",paddingLeft:parseInt(a.paddingLeft,10)+"px",paddingRight:parseInt(a.paddingRight,10)+"px",marginTop:Math.max(parseInt(o.getPropertyValue("margin-top"),10),e),marginLeft:Math.max(parseInt(o.getPropertyValue("margin-left"),10),s)})}hide(){n.J.safeRemove(this.placeholderElm)}toggle(){const t=this.j;t.editor&&!t.isInDestruct&&(t.getRealMode()===r.MODE_WYSIWYG&&(t=>{if(!t.firstChild)return!0;const e=t.firstChild;if(r.INSEPARABLE_TAGS.has(e.nodeName?.toLowerCase())||/^(TABLE)$/i.test(e.nodeName))return!1;const s=n.J.next(e,(t=>t&&!n.J.isEmptyTextNode(t)),t);return n.J.isText(e)&&!s?n.J.isEmptyTextNode(e):!s&&n.J.each(e,(t=>!(n.J.isLeaf(t)||n.J.isList(t))&&(n.J.isEmpty(t)||n.J.isTag(t,"br"))))})(t.editor)?this.show():this.hide())}beforeDestruct(t){this.hide(),t.e.off(".placeholder").off(window,"load",this.toggle)}}(0,i.Cg)([(0,o.debounce)((t=>t.defaultTimeout/10),!0)],h.prototype,"toggle",null),a.fg.add("placeholder",h)},81089(t,e,s){"use strict";s(56298).fg.add("poweredByJodit",(t=>{const{o:e}=t;e.hidePoweredByJodit||e.inline||!(e.showCharsCounter||e.showWordsCounter||e.showXPathInStatusbar)||t.hookStatus("ready",(()=>{t.statusbar.append(t.create.fromHTML('\n\t\t\t\t\t\t\tPowered by Jodit\n\t\t\t\t\t\t'),!0)}))}))},44921(t,e,s){"use strict";var i=s(17352),r=s(56298),o=s(98434);s(36115).T.prototype.controls.preview={icon:"eye",command:"preview",mode:i.MODE_SOURCE+i.MODE_WYSIWYG,tooltip:"Preview"},r.fg.add("preview",(t=>{t.registerButton({name:"preview"}),t.registerCommand("preview",((e,s,i)=>{const r=t.dlg();r.setSize(1024,600).open("",t.i18n("Preview")).setModal(!0);const[,n]=(0,o.u)(t,i,"px",r.getElm("content"));r.e.on(r,"afterClose",n)}))}))},11131(t,e,s){"use strict";s.d(e,{Y(){return r}});var i=s(42448);function r(t){const e=(t,e=t.ownerDocument.styleSheets)=>(0,i.$)(e).map((t=>{try{return(0,i.$)(t.cssRules)}catch{}return[]})).flat().filter((e=>{try{return!(!e||!t.matches(e.selectorText))}catch{}return!1}));class s{constructor(s,i,r){this.css={};const o=r||{},n=e=>{const s=e.selectorText.split(",").map((t=>t.trim())).sort().join(",");0==!!this.css[s]&&(this.css[s]={});const i=e.style.cssText.split(/;(?![A-Za-z0-9])/);for(let e=0;i.length>e;e++){if(!i[e])continue;const r=i[e].split(":");r[0]=r[0].trim(),r[1]=r[1].trim(),this.css[s][r[0]]=r[1].replace(/var\(([^)]+)\)/g,((e,s)=>{const[i,r]=s.split(",");return(t.ew.getComputedStyle(t.editor).getPropertyValue(i.trim())||r||e).trim()}))}};(()=>{const r=s.innerHeight,a=i.createTreeWalker(t.editor,NodeFilter.SHOW_ELEMENT,(()=>NodeFilter.FILTER_ACCEPT));for(;a.nextNode();){const t=a.currentNode;if(r>t.getBoundingClientRect().top||o.scanFullPage){const s=e(t);if(s)for(let t=0;s.length>t;t++)n(s[t])}}})()}generateCSS(){let t="";for(const e in this.css)if(!/:not\(/.test(e)){t+=e+" { ";for(const s in this.css[e])t+=s+": "+this.css[e][s]+"; ";t+="}\n"}return t}}try{return new s(t.ew,t.ed,{scanFullPage:!0}).generateCSS()}catch{}return""}},78757(t,e,s){"use strict";var i=s(17352),r=s(71842),o=s(56298),n=s(17527),a=s(98434),l=s(931),c=s(11131),u=s(59827),d=s.n(u),h=s(36115);l.I.set("print",d()),h.T.prototype.controls.print={exec(t){const e=t.create.element("iframe");Object.assign(e.style,{position:"fixed",right:0,bottom:0,width:0,height:0,border:0}),(0,o.My)(t,h.T).appendChild(e);const s=()=>{t.e.off(t.ow,"mousemove",s),r.J.safeRemove(e)},i=e.contentWindow;if(i){t.e.on(i,"onbeforeunload onafterprint",s).on(t.ow,"mousemove",s),t.o.iframe?(t.e.fire("generateDocumentStructure.iframe",i.document,t),i.document.body.innerHTML=t.value):(i.document.write('"),i.document.close(),(0,a.u)(t,void 0,"px",i.document.body));const e=i.document.createElement("style");e.innerHTML="@media print {\n\t\t\t\t\tbody {\n\t\t\t\t\t\t\t-webkit-print-color-adjust: exact;\n\t\t\t\t\t}\n\t\t\t}",i.document.head.appendChild(e),i.focus(),i.print()}},mode:i.MODE_SOURCE+i.MODE_WYSIWYG,tooltip:"Print"},o.fg.add("print",(t=>{t.registerButton({name:"print"})}))},60189(t,e,s){"use strict";var i=s(17352),r=s(56298),o=s(29866),n=s(931),a=s(34045),l=s.n(a),c=s(39199),u=s.n(c),d=s(36115);n.I.set("redo",l()).set("undo",u()),d.T.prototype.controls.redo={mode:i.MODE_SPLIT,isDisabled(t){return!t.history.canRedo()},tooltip:"Redo"},d.T.prototype.controls.undo={mode:i.MODE_SPLIT,isDisabled(t){return!t.history.canUndo()},tooltip:"Undo"},r.fg.add("redoUndo",class h extends o.k{constructor(){super(...arguments),this.buttons=[{name:"undo",group:"history"},{name:"redo",group:"history"}]}beforeDestruct(){}afterInit(t){const e=e=>(t.history[e](),!1);t.registerCommand("redo",{exec:e,hotkeys:["ctrl+y","ctrl+shift+z","cmd+y","cmd+shift+z"]}),t.registerCommand("undo",{exec:e,hotkeys:["ctrl+z","cmd+z"]})}})},36001(t,e,s){"use strict";s(36115).T.prototype.tableAllowCellResize=!0},39147(t,e,s){"use strict";var i=s(31635),r=s(17352),o=s(22664),n=s(55186),a=s(56298),l=s(65147),c=s(37435);s(36001);const u="table_processor_observer-resize";class d extends c.Plugin{constructor(){super(...arguments),this.selectMode=!1,this.resizeDelta=0,this.createResizeHandle=()=>{this.resizeHandler||(this.resizeHandler=this.j.c.div("jodit-table-resizer"),this.j.e.on(this.resizeHandler,"mousedown.table touchstart.table",this.onHandleMouseDown).on(this.resizeHandler,"mouseenter.table",(()=>{this.j.async.clearTimeout(this.hideTimeout)})))},this.hideTimeout=0,this.drag=!1,this.minX=0,this.maxX=0,this.startX=0}get module(){return this.j.getInstance("Table",this.j.o)}get isRTL(){return"rtl"===this.j.o.direction}showResizeHandle(){this.j.async.clearTimeout(this.hideTimeout),this.j.workplace.appendChild(this.resizeHandler)}hideResizeHandle(){this.hideTimeout=this.j.async.setTimeout((()=>{n.J.safeRemove(this.resizeHandler)}),{timeout:this.j.defaultTimeout,label:"hideResizer"})}onHandleMouseDown(t){if(this.j.isLocked)return;this.drag=!0,this.j.e.on(this.j.ow,"mouseup.resize-cells touchend.resize-cells",this.onMouseUp).on(this.j.ew,"mousemove.table touchmove.table",this.onMouseMove),this.startX=t.clientX,this.j.lock(u),this.resizeHandler.classList.add("jodit-table-resizer_moved");let e,s=this.workTable.getBoundingClientRect();if(this.minX=0,this.maxX=1e6,null!=this.wholeTable)s=this.workTable.parentNode.getBoundingClientRect(),this.minX=s.left,this.maxX=this.minX+s.width;else{const t=this.module.formalCoordinate(this.workTable,this.workCell,!0);this.module.formalMatrix(this.workTable,((s,i,o)=>{t[1]===o&&(e=s.getBoundingClientRect(),this.minX=Math.max(e.left+r.NEARBY/2,this.minX)),t[1]+(this.isRTL?-1:1)===o&&(e=s.getBoundingClientRect(),this.maxX=Math.min(e.left+e.width-r.NEARBY/2,this.maxX))}))}return!1}onMouseMove(t){if(!this.drag)return;this.j.e.fire("closeAllPopups");let e=t.clientX;const s=(0,l.offset)(this.resizeHandler.parentNode||this.j.od.documentElement,this.j,this.j.od,!0);this.minX>e&&(e=this.minX),e>this.maxX&&(e=this.maxX),this.resizeDelta=e-this.startX+(this.j.o.iframe?s.left:0),this.resizeHandler.style.left=e-(this.j.o.iframe?0:s.left)+"px";const i=this.j.s.sel;i&&i.removeAllRanges()}onMouseUp(t){(this.selectMode||this.drag)&&(this.selectMode=!1,this.j.unlock()),this.resizeHandler&&this.drag&&(this.drag=!1,this.j.e.off(this.j.ew,"mousemove.table touchmove.table",this.onMouseMove),this.resizeHandler.classList.remove("jodit-table-resizer_moved"),this.startX!==t.clientX&&(null==this.wholeTable?this.resizeColumns():this.resizeTable()),this.j.synchronizeValues(),this.j.s.focus())}resizeColumns(){const t=this.resizeDelta,e=[],s=this.module;s.setColumnWidthByDelta(this.workTable,s.formalCoordinate(this.workTable,this.workCell,!0)[1],t,!0,e);const i=(0,l.call)(this.isRTL?n.J.prev:n.J.next,this.workCell,n.J.isCell,this.workCell.parentNode);s.setColumnWidthByDelta(this.workTable,s.formalCoordinate(this.workTable,i)[1],-t,!1,e)}resizeTable(){const t=this.resizeDelta*(this.isRTL?-1:1),e=this.workTable.offsetWidth,s=(0,l.getContentWidth)(this.workTable.parentNode,this.j.ew),i=!this.wholeTable;if(this.isRTL?!i:i)this.workTable.style.width=(e+t)/s*100+"%";else{const i=this.isRTL?"marginRight":"marginLeft",r=parseInt(this.j.ew.getComputedStyle(this.workTable)[i]||"0",10);this.workTable.style.width=(e-t)/s*100+"%",this.workTable.style[i]=(r+t)/s*100+"%"}}setWorkCell(t,e=null){this.wholeTable=e,this.workCell=t,this.workTable=n.J.up(t,(t=>n.J.isTag(t,"table")),this.j.editor)}calcHandlePosition(t,e,s=0,i=0){const o=(0,l.offset)(e,this.j,this.j.ed);if(s>r.NEARBY&&o.width-r.NEARBY>s)return void this.hideResizeHandle();const a=(0,l.offset)(this.j.workplace,this.j,this.j.od,!0),c=(0,l.offset)(t,this.j,this.j.ed);if(this.resizeHandler.style.left=(s>r.NEARBY?o.left+o.width:o.left)-a.left+i+"px",Object.assign(this.resizeHandler.style,{height:c.height+"px",top:c.top-a.top+"px"}),this.showResizeHandle(),s>r.NEARBY){const t=(0,l.call)(this.isRTL?n.J.prev:n.J.next,e,n.J.isCell,e.parentNode);this.setWorkCell(e,!!t&&null)}else{const t=(0,l.call)(this.isRTL?n.J.next:n.J.prev,e,n.J.isCell,e.parentNode);this.setWorkCell(t||e,!t||null)}}afterInit(t){t.o.tableAllowCellResize&&t.e.off(this.j.ow,".resize-cells").off(".resize-cells").on("change.resize-cells afterCommand.resize-cells afterSetMode.resize-cells",(()=>{(0,l.$$)("table",t.editor).forEach(this.observe)})).on(this.j.ow,"scroll.resize-cells",(()=>{if(!this.drag)return;const e=n.J.up(this.workCell,(t=>n.J.isTag(t,"table")),t.editor);if(e){const t=e.getBoundingClientRect();this.resizeHandler.style.top=t.top+"px"}})).on("beforeSetMode.resize-cells",(()=>{const e=this.module;e.getAllSelectedCells().forEach((s=>{e.removeSelection(s),e.normalizeTable(n.J.closest(s,"table",t.editor))}))}))}observe(t){(0,l.dataBind)(t,u)||((0,l.dataBind)(t,u,!0),this.j.e.on(t,"mouseleave.resize-cells",(t=>{this.resizeHandler&&this.resizeHandler!==t.relatedTarget&&this.hideResizeHandle()})).on(t,"mousemove.resize-cells touchmove.resize-cells",this.j.async.throttle((e=>{if(this.j.isLocked)return;const s=n.J.up(e.target,n.J.isCell,t);s&&this.calcHandlePosition(t,s,e.offsetX)}),{timeout:this.j.defaultTimeout})),this.createResizeHandle())}beforeDestruct(t){t.events&&(t.e.off(this.j.ow,".resize-cells"),t.e.off(".resize-cells"))}}(0,i.Cg)([o.autobind],d.prototype,"onHandleMouseDown",null),(0,i.Cg)([o.autobind],d.prototype,"onMouseMove",null),(0,i.Cg)([o.autobind],d.prototype,"onMouseUp",null),(0,i.Cg)([o.autobind],d.prototype,"observe",null),a.fg.add("resizeCells",d)},57362(t,e,s){"use strict";var i=s(36115);i.T.prototype.allowResizeX=!1,i.T.prototype.allowResizeY=!0},76693(t,e,s){"use strict";var i=s(31635),r=s(22664),o=s(71842),n=s(56298),a=s(71005),l=s(53048);s(57362);let c=class t extends a.k{constructor(){super(...arguments),this.isResized=!1,this.start={x:0,y:0,w:0,h:0},this.handle=this.j.c.div("jodit-editor__resize",l.In.get("resize_handler"))}afterInit(t){const{height:e,width:s,allowResizeX:i}=t.o;let{allowResizeY:r}=t.o;"auto"===e&&"auto"!==s&&(r=!1),"auto"===e&&"auto"===s||!i&&!r||(t.statusbar.setMod("resize-handle",!0),t.e.on("toggleFullSize.resizeHandler",(()=>{this.handle.style.display=t.isFullSize?"none":"block"})).on(this.handle,"mousedown touchstart",this.onHandleResizeStart).on(t.ow,"mouseup touchend",this.onHandleResizeEnd),t.container.appendChild(this.handle))}onHandleResizeStart(t){this.isResized=!0,this.start.x=t.clientX,this.start.y=t.clientY,this.start.w=this.j.container.offsetWidth,this.start.h=this.j.container.offsetHeight,this.j.lock(),this.j.e.on(this.j.ow,"mousemove touchmove",this.onHandleResize),t.preventDefault()}onHandleResize(t){this.isResized&&(this.j.o.allowResizeY&&this.j.e.fire("setHeight",this.start.h+t.clientY-this.start.y),this.j.o.allowResizeX&&this.j.e.fire("setWidth",this.start.w+t.clientX-this.start.x),this.j.e.fire("resize"))}onHandleResizeEnd(){this.isResized&&(this.isResized=!1,this.j.e.off(this.j.ow,"mousemove touchmove",this.onHandleResize),this.j.unlock())}beforeDestruct(){o.J.safeRemove(this.handle),this.j.e.off(this.j.ow,"mouseup touchsend",this.onHandleResizeEnd)}};c.requires=["size"],c=(0,i.Cg)([r.autobind],c),n.fg.add("resizeHandler",c)},69505(t,e,s){"use strict";var i=s(36115);i.T.prototype.allowResizeTags=new Set(["img","iframe","table","jodit"]),i.T.prototype.resizer={showSize:!0,hideSizeTimeout:1e3,forImageChangeAttributes:!0,min_width:10,min_height:10,useAspectRatio:new Set(["img"])}},6857(t,e,s){"use strict";var i=s(31635),r=s(17352),o=s(22664),n=s(55186),a=s(56298),l=s(65147),c=s(29866);s(69505);const u="__jodit-resizer_binded";class d extends c.k{constructor(){super(...arguments),this.LOCK_KEY="resizer",this.element=null,this.isResizeMode=!1,this.isShown=!1,this.startX=0,this.startY=0,this.width=0,this.height=0,this.ratio=0,this.rect=this.j.c.fromHTML(`
\n\t\t\t\t
\n\t\t\t\t
\n\t\t\t\t
\n\t\t\t\t
\n\t\t\t\t100x100\n\t\t\t
`),this.sizeViewer=this.rect.getElementsByTagName("span")[0],this.pointerX=0,this.pointerY=0,this.isAltMode=!1,this.onClickElement=t=>{this.isResizeMode||this.element===t&&this.isShown||(this.element=t,this.show(),n.J.isTag(this.element,"img")&&!this.element.complete&&this.j.e.one(this.element,"load",this.updateSize))},this.updateSize=()=>{if(!this.isInDestruct&&this.isShown&&this.element&&this.rect){const t=this.getWorkplacePosition(),e=(0,l.offset)(this.element,this.j,this.j.ed),s=parseInt(this.rect.style.left||"0",10),i=e.top-t.top,r=e.left-t.left;parseInt(this.rect.style.top||"0",10)===i&&s===r&&this.rect.offsetWidth===this.element.offsetWidth&&this.rect.offsetHeight===this.element.offsetHeight||((0,l.css)(this.rect,{top:i,left:r,width:this.element.offsetWidth,height:this.element.offsetHeight}),this.j.events&&(this.j.e.fire(this.element,"changesize"),isNaN(s)||this.j.e.fire("resize")))}},this.hideSizeViewer=()=>{this.sizeViewer.style.opacity="0"}}afterInit(t){(0,l.$$)("div",this.rect).forEach((e=>{t.e.on(e,"mousedown.resizer touchstart.resizer",this.onStartResizing.bind(this,e))})),a.RR.on("hideHelpers",this.hide),t.e.on("readonly",(t=>{t&&this.hide()})).on("afterInit changePlace",this.addEventListeners.bind(this)).on("afterGetValueFromEditor.resizer",(t=>{const e=/]+data-jodit_iframe_wrapper[^>]+>(.*?]*>.*?<\/iframe>.*?)<\/jodit>/gi;e.test(t.value)&&(t.value=t.value.replace(e,"$1"))})),this.addEventListeners(),this.__onChangeEditor()}onEditorClick(t){let e=t.target;const{editor:s,options:{allowResizeTags:i}}=this.j;for(;e&&e!==s;){if(n.J.isTag(e,i))return this.__bind(e),void this.onClickElement(e);e=e.parentNode}}addEventListeners(){const t=this.j;t.e.off(t.editor,".resizer").off(t.ow,".resizer").on(t.editor,"keydown.resizer",(t=>{this.isShown&&t.key===r.KEY_DELETE&&this.element&&!n.J.isTag(this.element,"table")&&this.onDelete(t)})).on(t.ow,"resize.resizer",this.updateSize).on("resize.resizer",this.updateSize).on([t.ow,t.editor],"scroll.resizer",(()=>{this.isShown&&!this.isResizeMode&&this.hide()})).on(t.ow,"keydown.resizer",this.onKeyDown).on(t.ow,"keyup.resizer",this.onKeyUp).on(t.ow,"mouseup.resizer touchend.resizer",this.onClickOutside)}onStartResizing(t,e){if(!this.element||!this.element.parentNode)return this.hide(),!1;this.handle=t,e.cancelable&&e.preventDefault(),e.stopImmediatePropagation(),this.width=this.element.offsetWidth,this.height=this.element.offsetHeight,this.ratio=this.width/this.height,this.isResizeMode=!0,this.startX=e.clientX,this.startY=e.clientY,this.pointerX=e.clientX,this.pointerY=e.clientY;const{j:s}=this;s.e.fire("hidePopup"),s.lock(this.LOCK_KEY),s.e.on(s.ow,"mousemove.resizer touchmove.resizer",this.onResize)}onEndResizing(){const{j:t}=this;t.unlock(),this.isResizeMode=!1,this.isAltMode=!1,t.synchronizeValues(),t.e.off(t.ow,"mousemove.resizer touchmove.resizer",this.onResize)}onResize(t){if(this.isResizeMode){if(!this.element)return;let e,s;if(this.pointerX=t.clientX,this.pointerY=t.clientY,this.j.options.iframe){const i=this.getWorkplacePosition();e=t.clientX+i.left-this.startX,s=t.clientY+i.top-this.startY}else e=this.pointerX-this.startX,s=this.pointerY-this.startY;const i=this.handle.className;let r=0,o=0;const a=this.j.o.resizer.useAspectRatio;!this.isAltMode&&(!0===a||a&&n.J.isTag(this.element,a))?(e?(r=this.width+(i.match(/left/)?-1:1)*e,o=Math.round(r/this.ratio)):(o=this.height+(i.match(/top/)?-1:1)*s,r=Math.round(o*this.ratio)),r>(0,l.innerWidth)(this.j.editor,this.j.ow)&&(r=(0,l.innerWidth)(this.j.editor,this.j.ow),o=Math.round(r/this.ratio))):(r=this.width+(i.match(/left/)?-1:1)*e,o=this.height+(i.match(/top/)?-1:1)*s),r>this.j.o.resizer.min_width&&this.applySize(this.element,"width",this.rect.parentNode.offsetWidth>r?r:"100%"),o>this.j.o.resizer.min_height&&this.applySize(this.element,"height",o),this.updateSize(),this.showSizeViewer(this.element.offsetWidth,this.element.offsetHeight),t.stopImmediatePropagation()}}onKeyDown(t){this.isAltMode=t.key===r.KEY_ALT,!this.isAltMode&&this.isResizeMode&&this.onEndResizing()}onKeyUp(){this.isAltMode&&this.isResizeMode&&this.element&&(this.width=this.element.offsetWidth,this.height=this.element.offsetHeight,this.ratio=this.width/this.height,this.startX=this.pointerX,this.startY=this.pointerY),this.isAltMode=!1}onClickOutside(t){if(this.isShown){if(!this.isResizeMode)return this.hide();t.stopImmediatePropagation(),this.onEndResizing()}}getWorkplacePosition(){return(0,l.offset)(this.rect.parentNode||this.j.od.documentElement,this.j,this.j.od,!0)}applySize(t,e,s){const i=n.J.isImage(t)&&this.j.o.resizer.forImageChangeAttributes;i&&(0,l.attr)(t,e,s),i&&!t.style[e]||(0,l.css)(t,e,s)}onDelete(t){this.element&&("JODIT"!==this.element.tagName?this.j.s.select(this.element):(n.J.safeRemove(this.element),this.hide(),t.preventDefault()))}__onChangeEditor(){this.isShown&&(this.element&&this.element.parentNode?this.updateSize():this.hide()),(0,l.$$)("iframe",this.j.editor).forEach(this.__bind)}__bind(t){if(!n.J.isHTMLElement(t)||!this.j.o.allowResizeTags.has(t.tagName.toLowerCase())||(0,l.dataBind)(t,u))return;let e;if((0,l.dataBind)(t,u,!0),n.J.isTag(t,"iframe")){const s=t;n.J.isHTMLElement(t.parentNode)&&(0,l.attr)(t.parentNode,"-jodit_iframe_wrapper")?t=t.parentNode:(e=this.j.createInside.element("jodit",{"data-jodit-temp":1,contenteditable:!1,draggable:!0,"data-jodit_iframe_wrapper":1}),(0,l.attr)(e,"style",(0,l.attr)(t,"style")),(0,l.css)(e,{display:"inline-block"===t.style.display?"inline-block":"block",width:t.offsetWidth,height:t.offsetHeight}),t.parentNode&&t.parentNode.insertBefore(e,t),e.appendChild(t),this.j.e.on(e,"click",(()=>{(0,l.attr)(e,"data-jodit-wrapper_active",!0)})),t=e),this.j.e.off(t,"mousedown.select touchstart.select").on(t,"mousedown.select touchstart.select",(()=>{this.j.s.select(t)})).off(t,"changesize").on(t,"changesize",(()=>{s.setAttribute("width",t.offsetWidth+"px"),s.setAttribute("height",t.offsetHeight+"px")}))}this.j.e.on(t,"dragstart",this.hide),!r.IS_ES_NEXT&&r.IS_IE&&this.j.e.on(t,"mousedown",(e=>{n.J.isTag(t,"img")&&e.preventDefault()}))}showSizeViewer(t,e){this.j.o.resizer.showSize&&(this.sizeViewer.offsetWidth>t||this.sizeViewer.offsetHeight>e?this.hideSizeViewer():(this.sizeViewer.style.opacity="1",this.sizeViewer.textContent=`${t} x ${e}`,this.j.async.setTimeout(this.hideSizeViewer,{timeout:this.j.o.resizer.hideSizeTimeout,label:"hideSizeViewer"})))}show(){this.j.o.readonly||this.isShown||(this.isShown=!0,this.rect.parentNode||((0,l.markOwner)(this.j,this.rect),this.j.workplace.appendChild(this.rect)),this.j.isFullSize&&(this.rect.style.zIndex=""+(0,l.css)(this.j.container,"zIndex")),this.updateSize())}hide(){this.isResizeMode||(this.isResizeMode=!1,this.isShown=!1,this.element=null,n.J.safeRemove(this.rect),(0,l.$$)("[data-jodit-wrapper_active='true']",this.j.editor).forEach((t=>(0,l.attr)(t,"data-jodit-wrapper_active",!1))))}beforeDestruct(t){this.hide(),a.RR.off("hideHelpers",this.hide),t.e.off(this.j.ow,".resizer").off(".resizer")}}(0,i.Cg)([(0,o.watch)(":click")],d.prototype,"onEditorClick",null),(0,i.Cg)([o.autobind],d.prototype,"onStartResizing",null),(0,i.Cg)([o.autobind],d.prototype,"onEndResizing",null),(0,i.Cg)([o.autobind],d.prototype,"onResize",null),(0,i.Cg)([o.autobind],d.prototype,"onKeyDown",null),(0,i.Cg)([o.autobind],d.prototype,"onKeyUp",null),(0,i.Cg)([o.autobind],d.prototype,"onClickOutside",null),(0,i.Cg)([(0,o.watch)(":change")],d.prototype,"__onChangeEditor",null),(0,i.Cg)([o.autobind],d.prototype,"__bind",null),(0,i.Cg)([o.autobind,(0,o.watch)(":hideResizer")],d.prototype,"hide",null),a.fg.add("resizer",d)},78593(t,e,s){"use strict";var i=s(931),r=s(21917),o=s.n(r),n=s(36115);n.T.prototype.useSearch=!0,n.T.prototype.search={lazyIdleTimeout:0,useCustomHighlightAPI:void 0!==window.Highlight},i.I.set("search",o()),n.T.prototype.controls.find={tooltip:"Find",icon:"search",exec(t,e,{control:s}){switch(s.args&&s.args[0]){case"findPrevious":t.e.fire("searchPrevious");break;case"findNext":t.e.fire("searchNext");break;case"replace":t.execCommand("openReplaceDialog");break;default:t.execCommand("openSearchDialog")}},list:{search:"Find",findNext:"Find Next",findPrevious:"Find Previous",replace:"Replace"},childTemplate(t,e,s){return s}}},89568(t,e,s){"use strict";s.d(e,{IJ(){return l},Tz(){return c},_B(){return n},zy(){return a}});var i=s(55186),r=s(58720);const o="jd-tmp-selection";function n(t,e,s,r,n){if(null==e.startContainer.nodeValue||null==e.endContainer.nodeValue)return;if(t.o.search.useCustomHighlightAPI&&void 0!==window.Highlight){const i=[e,...s].map((e=>{const s=t.selection.createRange();return s.setStart(e.startContainer,e.startOffset),s.setEnd(e.endContainer,e.endOffset),s})),r=new Highlight(...i);return CSS.highlights.clear(),CSS.highlights.set("jodit-search-result",r),void(s.length=0)}const a=r.element("span",{[o]:!0});i.J.markTemporary(a);const l=e.startContainer.nodeValue;let c=0;if(0!==e.startOffset){const t=r.text(l.substring(0,e.startOffset));e.startContainer.nodeValue=l.substring(e.startOffset),i.J.before(e.startContainer,t),e.startContainer===e.endContainer&&(c=e.startOffset,e.endOffset-=c),e.startOffset=0}const u=e.endContainer.nodeValue;if(e.endOffset!==u.length){const t=r.text(u.substring(e.endOffset));e.endContainer.nodeValue=u.substring(0,e.endOffset),i.J.after(e.endContainer,t);for(const i of s){if(i.startContainer!==e.endContainer)break;i.startContainer=t,i.startOffset=i.startOffset-e.endOffset-c,i.endContainer===e.endContainer&&(i.endContainer=t,i.endOffset=i.endOffset-e.endOffset-c)}e.endOffset=e.endContainer.nodeValue.length}let d=e.startContainer;do{if(!d)break;if(!i.J.isText(d)||i.J.isElement(h=d.parentNode)&&h.hasAttribute(o)||i.J.wrap(d,a.cloneNode(),r),d===e.endContainer)break;let t=d.firstChild||d.nextSibling;if(!t){for(;d&&!d.nextSibling&&d!==n;)d=d.parentNode;t=d?.nextSibling}d=t}while(d&&d!==n);var h}function a(t){return(0,r.$$)(`[${o}]`,t)}function l(t){a(t).forEach((t=>i.J.unwrap(t)))}function c(t){return t.replace(RegExp(`]+${o}[^>]+>(.*?)`,"g"),"$1")}},78817(t,e,s){"use strict";s.d(e,{IJ(){return i.IJ},QN(){return r.Q},Tz(){return i.Tz},_B(){return i._B},zy(){return i.zy}});var i=s(89568),r=s(30621)},30621(t,e,s){"use strict";s.d(e,{Q(){return r}});var i=s(67975);class r{constructor(t=i.H){this.searchIndex=t,this.queue=[],this.value=""}add(t){const e=(t.nodeValue??"").toLowerCase();if(!e.length)return;const s=this.value.length;this.queue.push({startIndex:s,endIndex:s+e.length,node:t}),this.value+=e}ranges(t,e=0){const s=[];let i=e,r=0,o=0;do{if([i,r]=this.searchIndex(t,this.value,i),-1!==i){let t,e,n=0,a=0;for(let s=o;this.queue.length>s;s+=1)if(!t&&this.queue[s].endIndex>i&&(t=this.queue[s].node,n=i-this.queue[s].startIndex),t&&this.queue[s].endIndex>=i+r){e=this.queue[s].node,a=i+r-this.queue[s].startIndex,o=s;break}t&&e&&s.push({startContainer:t,startOffset:n,endContainer:e,endOffset:a}),i+=r}}while(-1!==i);return 0===s.length?null:s}}},17343(t,e,s){"use strict";var i=s(31635),r=(s(17352),s(22664)),o=s(71842),n=s(56298),a=s(65147),l=s(71005),c=(s(78593),s(78817)),u=s(63064);class d extends l.k{constructor(){super(...arguments),this.buttons=[{name:"find",group:"search"}],this.previousQuery="",this.drawPromise=null,this.walker=null,this.walkerCount=null,this.cache={},this.wrapFrameRequest=0}get ui(){return new u.F(this.j)}async updateCounters(){this.ui.isOpened&&(this.ui.count=await this.calcCounts(this.ui.query))}onPressReplaceButton(){this.findAndReplace(this.ui.query),this.updateCounters()}tryScrollToElement(t){let e=o.J.closest(t,o.J.isElement,this.j.editor);e||(e=o.J.prev(t,o.J.isElement,this.j.editor)),e&&e!==this.j.editor&&(0,a.scrollIntoViewIfNeeded)(e,this.j.editor,this.j.ed)}async calcCounts(t){return(await this.findQueryBounds(t,"walkerCount")).length}async findQueryBounds(t,e){let s=this[e];return s&&s.break(),s=new o.p(this.j.async,{timeout:this.j.o.search.lazyIdleTimeout}),this[e]=s,this.find(s,t).catch((t=>[]))}async findAndReplace(t){const e=await this.findQueryBounds(t,"walker");if(!e.length)return!1;let s=this.findCurrentIndexInRanges(e,this.j.s.range);-1===s&&(s=0);const i=e[s];if(i){try{const e=this.j.ed.createRange();e.setStart(i.startContainer,i.startOffset),e.setEnd(i.endContainer,i.endOffset),e.deleteContents();const r=this.j.createInside.text(this.ui.replace);o.J.safeInsertNode(e,r),(0,c.IJ)(this.j.editor),this.j.s.setCursorAfter(r),this.tryScrollToElement(r),this.cache={},this.ui.currentIndex=s,await this.findAndSelect(t,!0).catch((t=>null))}finally{this.j.synchronizeValues()}return this.j.e.fire("afterFindAndReplace"),!0}return!1}async findAndSelect(t,e){const s=await this.findQueryBounds(t,"walker");if(!s.length)return!1;this.previousQuery===t&&(0,c.zy)(this.j.editor).length||(this.drawPromise?.rejectCallback(),this.j.async.cancelAnimationFrame(this.wrapFrameRequest),(0,c.IJ)(this.j.editor),this.drawPromise=this.__drawSelectionRanges(s)),this.previousQuery=t;let i=this.ui.currentIndex-1;i=-1===i?0:e?i===s.length-1?0:i+1:0===i?s.length-1:i-1,this.ui.currentIndex=i+1;const r=s[i];if(r){const t=this.j.ed.createRange();try{t.setStart(r.startContainer,r.startOffset),t.setEnd(r.endContainer,r.endOffset),this.j.s.selectRange(t)}catch(t){}return this.tryScrollToElement(r.startContainer),await this.updateCounters(),await this.drawPromise,this.j.e.fire("afterFindAndSelect"),!0}return!1}findCurrentIndexInRanges(t,e){return t.findIndex((t=>t.startContainer===e.startContainer&&t.startOffset===e.startOffset&&t.endContainer===e.startContainer&&t.endOffset===e.endOffset))}async isValidCache(t){return(await t).every((t=>t.startContainer.isConnected&&(t.startContainer.nodeValue?.length??0)>=t.startOffset&&t.endContainer.isConnected&&(t.endContainer.nodeValue?.length??0)>=t.endOffset))}async find(t,e){if(!e.length)return[];const s=this.cache[e];return s&&await this.isValidCache(s)?s:(this.cache[e]=this.j.async.promise((s=>{const i=new c.QN(this.j.o.search.fuzzySearch);t.on("break",(()=>{s([])})).on("visit",(t=>(o.J.isText(t)&&i.add(t),!1))).on("end",(()=>{s(i.ranges(e)??[])})).setWork(this.j.editor)})),this.cache[e])}__drawSelectionRanges(t){const{async:e,createInside:s,editor:i}=this.j;e.cancelAnimationFrame(this.wrapFrameRequest);const r=[...t];let o,n=0;return e.promise((t=>{const a=()=>{do{o=r.shift(),o&&(0,c._B)(this.j,o,r,s,i),n+=1}while(o&&5>=n);r.length?this.wrapFrameRequest=e.requestAnimationFrame(a):t()};a()}))}onAfterGetValueFromEditor(t){t.value=(0,c.Tz)(t.value)}afterInit(t){if(t.o.useSearch){const e=this;t.e.on("beforeSetMode.search",(()=>{this.ui.close()})).on(this.ui,"afterClose",(()=>{(0,c.IJ)(t.editor),this.ui.currentIndex=0,this.ui.count=0,this.cache={}})).on("click",(()=>{this.ui.currentIndex=0,(0,c.IJ)(t.editor)})).on("change.search",(()=>{this.cache={}})).on("keydown.search mousedown.search",t.async.debounce((()=>{this.ui.selInfo&&(t.s.removeMarkers(),this.ui.selInfo=null),this.ui.isOpened&&this.updateCounters()}),t.defaultTimeout)).on("searchNext.search searchPrevious.search",(()=>(this.ui.isOpened||this.ui.open(),e.findAndSelect(e.ui.query,"searchNext"===t.e.current).catch((t=>{}))))).on("search.search",((t,s=!0)=>(this.ui.currentIndex=0,e.findAndSelect(t||"",s).catch((t=>{}))))),t.registerCommand("search",{exec(t,s,i=!0){return s&&e.findAndSelect(s,i).catch((t=>{})),!1}}).registerCommand("openSearchDialog",{exec(t,s){return e.ui.open(s),!1},hotkeys:["ctrl+f","cmd+f"]}).registerCommand("openReplaceDialog",{exec(s,i,r){return t.o.readonly||e.ui.open(i,r,!0),!1},hotkeys:["ctrl+h","cmd+h"]})}}beforeDestruct(t){this.ui.destruct(),t.e.off(".search")}}(0,i.Cg)([r.cache],d.prototype,"ui",null),(0,i.Cg)([(0,r.watch)("ui:needUpdateCounters")],d.prototype,"updateCounters",null),(0,i.Cg)([(0,r.watch)("ui:pressReplaceButton")],d.prototype,"onPressReplaceButton",null),(0,i.Cg)([r.autobind],d.prototype,"findQueryBounds",null),(0,i.Cg)([r.autobind],d.prototype,"findAndReplace",null),(0,i.Cg)([r.autobind],d.prototype,"findAndSelect",null),(0,i.Cg)([r.autobind],d.prototype,"find",null),(0,i.Cg)([(0,r.watch)(":afterGetValueFromEditor")],d.prototype,"onAfterGetValueFromEditor",null),n.fg.add("search",d)},63064(t,e,s){"use strict";s.d(e,{F(){return c}});var i=s(31635),r=s(17352),o=s(22664),n=s(71842),a=s(65147),l=s(53048);let c=class t extends l.D${className(){return"UISearch"}render(){return`
\n\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t\n\t\t\t\t\t\t0/0\n\t\t\t\t\t\n\t\t\t\t
\n\t\t\t\t
\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
\n\t\t\t
\n\t\t
`}get currentIndex(){return this._currentIndex}set currentIndex(t){this._currentIndex=t,this.currentBox.innerText=""+t}set count(t){this.countBox.innerText=""+t}get query(){return this.queryInput.value}get replace(){return this.replaceInput.value}constructor(t){super(t),this.selInfo=null,this._currentIndex=0,this.isOpened=!1;const{query:e,replace:s,cancel:i,next:o,prev:n,replaceBtn:l,current:c,count:u}=(0,a.refs)(this.container);this.queryInput=e,this.replaceInput=s,this.closeButton=i,this.replaceButton=l,this.currentBox=c,this.countBox=u,t.e.on(this.closeButton,"pointerdown",(()=>(this.close(),!1))).on(this.queryInput,"input",(()=>{this.currentIndex=0})).on(this.queryInput,"pointerdown",(()=>{t.s.isFocused()&&(t.s.removeMarkers(),this.selInfo=t.s.save())})).on(this.replaceButton,"pointerdown",(()=>(t.e.fire(this,"pressReplaceButton"),!1))).on(o,"pointerdown",(()=>(t.e.fire("searchNext"),!1))).on(n,"pointerdown",(()=>(t.e.fire("searchPrevious"),!1))).on(this.queryInput,"input",(()=>{this.setMod("empty-query",!(0,a.trim)(this.queryInput.value).length)})).on(this.queryInput,"keydown",this.j.async.debounce((e=>{e.key===r.KEY_ENTER?(e.preventDefault(),e.stopImmediatePropagation(),t.e.fire("searchNext")&&this.close()):t.e.fire(this,"needUpdateCounters")}),this.j.defaultTimeout))}onEditorKeyDown(t){if(!this.isOpened)return;const{j:e}=this;if(e.getRealMode()===r.MODE_WYSIWYG)switch(t.key){case r.KEY_ESC:this.close();break;case r.KEY_F3:this.queryInput.value&&(e.e.fire(t.shiftKey?"searchPrevious":"searchNext"),t.preventDefault())}}open(t,e,s=!1){this.isOpened||(this.j.workplace.appendChild(this.container),this.isOpened=!0),this.calcSticky(this.j.e.fire("getStickyState.sticky")||!1),this.j.e.fire("hidePopup"),this.setMod("replace",s);const i=t??""+(this.j.s.sel||"");i&&(this.queryInput.value=i),e&&(this.replaceInput.value=e),this.setMod("empty-query",!i.length),this.j.e.fire(this,"needUpdateCounters"),i?this.queryInput.select():this.queryInput.focus()}close(){this.isOpened&&(this.j.s.restore(),n.J.safeRemove(this.container),this.isOpened=!1,this.j.e.fire(this,"afterClose"))}calcSticky(t){if(this.isOpened)if(this.setMod("sticky",t),t){const t=(0,a.position)(this.j.toolbarContainer);(0,a.css)(this.container,{top:t.top+t.height,left:t.left+t.width})}else(0,a.css)(this.container,{top:null,left:null})}};(0,i.Cg)([(0,o.watch)([":keydown","queryInput:keydown"])],c.prototype,"onEditorKeyDown",null),(0,i.Cg)([o.autobind],c.prototype,"open",null),(0,i.Cg)([o.autobind],c.prototype,"close",null),(0,i.Cg)([(0,o.watch)(":toggleSticky")],c.prototype,"calcSticky",null),c=(0,i.Cg)([o.component],c)},29581(t,e,s){"use strict";s(36115).T.prototype.tableAllowCellSelection=!0},46939(t,e,s){"use strict";var i=s(31635),r=s(17352),o=s(22664),n=s(55186),a=s(56298),l=s(65147),c=s(71005),u=s(11648);s(29581);const d="table_processor_observer",h="onMoveTableSelectCell";class p extends c.k{constructor(){super(...arguments),this.__selectedCell=null,this.__isSelectionMode=!1}get __tableModule(){return this.j.getInstance(u.X,this.j.o)}afterInit(t){t.o.tableAllowCellSelection&&t.e.on("keydown.select-cells",(t=>{t.key===r.KEY_TAB&&this.unselectCells()})).on("beforeCommand.select-cells",this.onExecCommand).on("afterCommand.select-cells",this.onAfterCommand).on(["clickEditor","mousedownTd","mousedownTh","touchstartTd","touchstartTh"].map((t=>t+".select-cells")).join(" "),this.onStartSelection).on("clickTr clickTbody",(()=>{const t=this.__tableModule.getAllSelectedCells().length;if(t)return t>1&&this.j.s.sel?.removeAllRanges(),!1}))}onStartSelection(t){if(this.j.o.readonly)return;if(this.unselectCells(),t===this.j.editor)return;const e=n.J.closest(t,"table",this.j.editor);return t&&e?(t.firstChild||t.appendChild(this.j.createInside.element("br")),this.__isSelectionMode=!0,this.__selectedCell=t,this.__tableModule.addSelection(t),this.j.e.on(e,"mousemove.select-cells touchmove.select-cells",this.j.async.throttle(this.__onMove.bind(this,e),{label:h,timeout:this.j.defaultTimeout/2})).on(e,"mouseup.select-cells touchend.select-cells",this.__onStopSelection.bind(this,e)),!1):void 0}onOutsideClick(){this.__selectedCell=null,this.__onRemoveSelection()}onChange(){this.j.isLocked||this.__isSelectionMode||this.__onRemoveSelection()}__onMove(t,e){if(this.j.o.readonly&&!this.j.isLocked)return;if(this.j.isLockedNotBy(d))return;const s=this.j.ed.elementFromPoint(e.clientX,e.clientY);if(!s)return;const i=n.J.closest(s,["td","th"],t);if(!i||!this.__selectedCell)return;i!==this.__selectedCell&&this.j.lock(d),this.unselectCells();const r=this.__tableModule.getSelectedBound(t,[i,this.__selectedCell]),o=this.__tableModule.formalMatrix(t);for(let t=r[0][0];r[1][0]>=t;t+=1)for(let e=r[0][1];r[1][1]>=e;e+=1)this.__tableModule.addSelection(o[t][e]);this.__tableModule.getAllSelectedCells().length>1&&this.j.s.sel?.removeAllRanges(),this.j.e.fire("hidePopup"),e.stopPropagation(),(()=>{const t=this.j.createInside.fromHTML('
 
');i.appendChild(t),this.j.async.setTimeout((()=>{t.parentNode?.removeChild(t)}),this.j.defaultTimeout/5)})()}__onRemoveSelection(t){if(!t?.buffer?.actionTrigger&&!this.__selectedCell&&this.__tableModule.getAllSelectedCells().length)return this.j.unlock(),this.unselectCells(),void this.j.e.fire("hidePopup","cells");this.__isSelectionMode=!1,this.__selectedCell=null}__onStopSelection(t,e){if(!this.__selectedCell)return;this.__isSelectionMode=!1,this.j.unlock();const s=this.j.ed.elementFromPoint(e.clientX,e.clientY);if(!s)return;const i=n.J.closest(s,["td","th"],t);if(!i)return;const r=n.J.closest(i,"table",t);if(r&&r!==t)return;const o=this.__tableModule.getSelectedBound(t,[i,this.__selectedCell]),a=this.__tableModule.formalMatrix(t),c=a[o[1][0]][o[1][1]],u=a[o[0][0]][o[0][1]];this.j.e.fire("showPopup",t,(()=>{const t=(0,l.position)(u,this.j),e=(0,l.position)(c,this.j);return{left:t.left,top:t.top,width:e.left-t.left+e.width,height:e.top-t.top+e.height}}),"cells"),(0,l.$$)("table",this.j.editor).forEach((t=>{this.j.e.off(t,"mousemove.select-cells touchmove.select-cells mouseup.select-cells touchend.select-cells")})),this.j.async.clearTimeout(h)}unselectCells(t){const e=this.__tableModule,s=e.getAllSelectedCells();s.length&&s.forEach((s=>{t&&t===s||e.removeSelection(s)}))}onExecCommand(t){if(/table(splitv|splitg|merge|empty|bin|binrow|bincolumn|addcolumn|addrow)/.test(t)){t=t.replace("table","");const e=this.__tableModule.getAllSelectedCells();if(e.length){const[s]=e;if(!s)return;const i=n.J.closest(s,"table",this.j.editor);if(!i)return;switch(t){case"splitv":this.__tableModule.splitVertical(i);break;case"splitg":this.__tableModule.splitHorizontal(i);break;case"merge":this.__tableModule.mergeSelected(i);break;case"empty":e.forEach((t=>n.J.detach(t)));break;case"bin":n.J.safeRemove(i);break;case"binrow":new Set(e.map((t=>t.parentNode))).forEach((t=>{this.__tableModule.removeRow(i,t.rowIndex)}));break;case"bincolumn":{const t=new Set;e.reduce(((e,s)=>(t.has(s.cellIndex)||(e.push(s),t.add(s.cellIndex)),e)),[]).forEach((t=>{this.__tableModule.removeColumn(i,t.cellIndex)}))}break;case"addcolumnafter":case"addcolumnbefore":this.__tableModule.appendColumn(i,s.cellIndex,"addcolumnafter"===t);break;case"addrowafter":case"addrowbefore":this.__tableModule.appendRow(i,s.parentNode,"addrowafter"===t)}}return!1}}onAfterCommand(t){/^justify/.test(t)&&this.__tableModule.getAllSelectedCells().forEach((e=>(0,l.alignElement)(t,e)))}beforeDestruct(t){this.__onRemoveSelection(),t.e.off(".select-cells")}}p.requires=["select"],(0,i.Cg)([o.autobind],p.prototype,"onStartSelection",null),(0,i.Cg)([(0,o.watch)(":outsideClick")],p.prototype,"onOutsideClick",null),(0,i.Cg)([(0,o.watch)(":change")],p.prototype,"onChange",null),(0,i.Cg)([o.autobind],p.prototype,"__onRemoveSelection",null),(0,i.Cg)([o.autobind],p.prototype,"__onStopSelection",null),(0,i.Cg)([o.autobind],p.prototype,"onExecCommand",null),(0,i.Cg)([o.autobind],p.prototype,"onAfterCommand",null),a.fg.add("selectCells",p)},41133(t,e,s){"use strict";s(36115).T.prototype.select={normalizeSelectionBeforeCutAndCopy:!1,normalizeTripleClick:!0}},35523(t,e,s){"use strict";var i=s(31635),r=s(22664),o=s(55186),n=s(56298),a=s(83260),l=s(71005),c=s(53048);s(41133);class u extends l.k{constructor(){super(...arguments),this.proxyEventsList=["click","mousedown","touchstart","mouseup","touchend"]}afterInit(t){this.proxyEventsList.forEach((e=>{t.e.on(e+".select",this.onStartSelection)}))}beforeDestruct(t){this.proxyEventsList.forEach((e=>{t.e.on(e+".select",this.onStartSelection)}))}onStartSelection(t){const{j:e}=this;let s,i=t.target;for(;void 0===s&&i&&i!==e.editor;)s=e.e.fire((0,a.x)(t.type+"_"+i.nodeName.toLowerCase()),i,t),i=i.parentElement;"click"===t.type&&void 0===s&&i===e.editor&&e.e.fire(t.type+"Editor",i,t)}onOutsideClick(t){const e=t.target;o.J.up(e,(t=>t===this.j.editor))||c.D$.closestElement(e,c.zD)||this.j.e.fire("outsideClick",t)}beforeCommandCut(){const{s:t}=this.j;if(!t.isCollapsed()){const e=t.current();e&&o.J.isOrContains(this.j.editor,e)&&this.onCopyNormalizeSelectionBound()}}beforeCommandSelectAll(){const{s:t}=this.j;return t.focus(),t.select(this.j.editor,!0),t.expandSelection(),!1}onTripleClickNormalizeSelection(t){if(3!==t.detail||!this.j.o.select.normalizeTripleClick)return;const{s:e}=this.j,{startContainer:s,startOffset:i}=e.range;0===i&&o.J.isText(s)&&e.select(o.J.closest(s,o.J.isBlock,this.j.editor)||s,!0)}onCopyNormalizeSelectionBound(t){const{s:e,editor:s,o:i}=this.j;i.select.normalizeSelectionBeforeCutAndCopy&&!e.isCollapsed()&&(!t||t.isTrusted&&o.J.isNode(t.target)&&o.J.isOrContains(s,t.target))&&this.jodit.s.expandSelection()}}(0,i.Cg)([r.autobind],u.prototype,"onStartSelection",null),(0,i.Cg)([(0,r.watch)("ow:click")],u.prototype,"onOutsideClick",null),(0,i.Cg)([(0,r.watch)([":beforeCommandCut"])],u.prototype,"beforeCommandCut",null),(0,i.Cg)([(0,r.watch)([":beforeCommandSelectall"])],u.prototype,"beforeCommandSelectAll",null),(0,i.Cg)([(0,r.watch)([":click"])],u.prototype,"onTripleClickNormalizeSelection",null),(0,i.Cg)([(0,r.watch)([":copy",":cut"])],u.prototype,"onCopyNormalizeSelectionBound",null),n.fg.add("select",u)},78134(t,e,s){"use strict";var i=s(36115);i.T.prototype.minWidth=200,i.T.prototype.maxWidth="100%",i.T.prototype.minHeight=200,i.T.prototype.maxHeight="auto",i.T.prototype.saveHeightInStorage=!1},69077(t,e,s){"use strict";var i=s(31635),r=s(22664),o=s(56298),n=s(2461),a=s(38322),l=s(29866);s(78134);let c=class t extends l.k{constructor(){super(...arguments),this.__resizeWorkspaces=this.j.async.debounce(this.__resizeWorkspaceImd,this.j.defaultTimeout,!0)}afterInit(t){t.e.on("setHeight.size",this.__setHeight).on("setWidth.size",this.__setWidth).on("afterInit.size changePlace.size",this.__initialize,{top:!0}).on(t.ow,"load.size",this.__resizeWorkspaces).on("afterInit.size resize.size afterUpdateToolbar.size scroll.size afterResize.size",this.__resizeWorkspaces).on("toggleFullSize.size toggleToolbar.size",this.__resizeWorkspaceImd),this.__initialize()}__initialize(){const{j:t}=this;if(t.o.inline)return;let{height:e}=t.o;if(t.o.saveHeightInStorage&&"auto"!==e){const s=t.storage.get("height");s&&(e=s)}(0,a.A)(t.editor,{minHeight:"100%"}),(0,a.A)(t.container,{minHeight:t.o.minHeight,maxHeight:t.o.maxHeight,minWidth:t.o.minWidth,maxWidth:t.o.maxWidth}),t.isFullSize||(this.__setHeight(e),this.__setWidth(t.o.width))}__setHeight(t){if((0,n.E)(t)){const{minHeight:e,maxHeight:s}=this.j.o;(0,n.E)(e)&&e>t&&(t=e),(0,n.E)(s)&&t>s&&(t=s)}(0,a.A)(this.j.container,"height",t),this.j.o.saveHeightInStorage&&this.j.storage.set("height",t),this.__resizeWorkspaceImd()}__setWidth(t){if((0,n.E)(t)){const{minWidth:e,maxWidth:s}=this.j.o;(0,n.E)(e)&&e>t&&(t=e),(0,n.E)(s)&&t>s&&(t=s)}(0,a.A)(this.j.container,"width",t),this.__resizeWorkspaceImd()}__getNotWorkHeight(){return(this.j.toolbarContainer?.offsetHeight||0)+(this.j.statusbar?.getHeight()||0)+2}__resizeWorkspaceImd(){if(!this.j||this.j.isDestructed||!this.j.o||this.j.o.inline)return;if(!this.j.container||!this.j.container.parentNode)return;const t=((0,a.A)(this.j.container,"minHeight")||0)-this.__getNotWorkHeight();if((0,n.E)(t)&&t>0&&([this.j.workplace,this.j.iframe,this.j.editor].map((e=>{e&&(0,a.A)(e,"minHeight",t)})),this.j.e.fire("setMinHeight",t)),(0,n.E)(this.j.o.maxHeight)){const t=this.j.o.maxHeight-this.__getNotWorkHeight();[this.j.workplace,this.j.iframe,this.j.editor].map((e=>{e&&(0,a.A)(e,"maxHeight",t)})),this.j.e.fire("setMaxHeight",t)}this.j.container&&(0,a.A)(this.j.workplace,"height","auto"!==this.j.o.height||this.j.isFullSize?this.j.container.offsetHeight-this.__getNotWorkHeight():"auto")}beforeDestruct(t){t.e.off(t.ow,"load.size",this.__resizeWorkspaces).off(".size")}};(0,i.Cg)([(0,r.throttle)()],c.prototype,"__initialize",null),(0,i.Cg)([r.autobind],c.prototype,"__resizeWorkspaceImd",null),c=(0,i.Cg)([r.autobind],c),o.fg.add("size",c)},90722(t,e,s){"use strict";var i=s(17352),r=s(931),o=s(9103),n=s.n(o),a=s(36115);a.T.prototype.beautifyHTML=!i.IS_IE,a.T.prototype.sourceEditor="ace",a.T.prototype.sourceEditorNativeOptions={showGutter:!0,theme:"ace/theme/idle_fingers",mode:"ace/mode/html",wrap:!0,highlightActiveLine:!0},a.T.prototype.sourceEditorCDNUrlsJS=["https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.2/ace.js"],a.T.prototype.beautifyHTMLCDNUrlsJS=["https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.4/beautify.min.js","https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.14.4/beautify-html.min.js"],r.I.set("source",n()),a.T.prototype.controls.source={mode:i.MODE_SPLIT,exec(t){t.toggleMode()},isActive(t){return t.getRealMode()===i.MODE_SOURCE},tooltip:"Change mode"}},5533(t,e,s){"use strict";s.d(e,{p(){return n}});var i=s(17352),r=s(65147),o=s(53380);class n extends o.F{constructor(){super(...arguments),this.className="jodit_ace_editor",this.proxyOnBlur=t=>{this.j.e.fire("blur",t)},this.proxyOnFocus=t=>{this.j.e.fire("focus",t)},this.proxyOnMouseDown=t=>{this.j.e.fire("mousedown",t)}}aceExists(){return void 0!==this.j.ow.ace}getLastColumnIndex(t){return this.instance.session.getLine(t).length}getLastColumnIndices(){const t=this.instance.session.getLength(),e=[];let s=0;for(let i=0;t>i;i++)s+=this.getLastColumnIndex(i),i>0&&(s+=1),e[i]=s;return e}getRowColumnIndices(t){const e=this.getLastColumnIndices();if(e[0]>=t)return{row:0,column:t};let s=1;for(let i=1;e.length>i;i++)t>e[i]&&(s=i+1);return{row:s,column:t-e[s-1]-1}}setSelectionRangeIndices(t,e){const s=this.getRowColumnIndices(t),i=this.getRowColumnIndices(e);this.instance.getSelection().setSelectionRange({start:s,end:i})}getIndexByRowColumn(t,e){return this.getLastColumnIndices()[t]-this.getLastColumnIndex(t)+e}init(t){const e=()=>{if(void 0!==this.instance||!this.aceExists())return;const e=this.j.c.div("jodit-source__mirror-fake");this.container.appendChild(e),this.instance=t.ow.ace.edit(e),this.instance.setTheme(t.o.sourceEditorNativeOptions.theme),this.instance.renderer.setShowGutter(t.o.sourceEditorNativeOptions.showGutter),this.instance.getSession().setMode(t.o.sourceEditorNativeOptions.mode),this.instance.setHighlightActiveLine(t.o.sourceEditorNativeOptions.highlightActiveLine),this.instance.getSession().setUseWrapMode(!0),this.instance.setOption("indentedSoftWrap",!1),this.instance.setOption("wrap",t.o.sourceEditorNativeOptions.wrap),this.instance.getSession().setUseWorker(!1),this.instance.$blockScrolling=1/0,this.instance.on("change",this.toWYSIWYG),this.instance.on("focus",this.proxyOnFocus),this.instance.on("mousedown",this.proxyOnMouseDown),this.instance.on("blur",this.proxyOnBlur),t.getRealMode()!==i.MODE_WYSIWYG&&this.setValue(this.getValue());const s=this.j.async.debounce((()=>{t.isInDestruct||(this.instance.setOption("maxLines","auto"!==t.o.height?t.workplace.offsetHeight/this.instance.renderer.lineHeight:1/0),this.instance.resize())}),2*this.j.defaultTimeout);t.e.on("afterResize afterSetMode",s),s(),this.onReady()};t.e.on("afterSetMode",(()=>{t.getRealMode()!==i.MODE_SOURCE&&t.getMode()!==i.MODE_SPLIT||(this.fromWYSIWYG(),e())})),e(),this.aceExists()||(0,r.loadNext)(t,t.o.sourceEditorCDNUrlsJS).then((()=>{t.isInDestruct||e()})).catch((()=>null))}destruct(){this.instance.off("change",this.toWYSIWYG),this.instance.off("focus",this.proxyOnFocus),this.instance.off("mousedown",this.proxyOnMouseDown),this.instance.destroy(),this.j?.events?.off("aceInited.source")}setValue(t){if(!this.j.o.editHTMLDocumentMode&&this.j.o.beautifyHTML){const e=this.j.e.fire("beautifyHTML",t);(0,r.isString)(e)&&(t=e)}this.instance.setValue(t),this.instance.clearSelection()}getValue(){return this.instance.getValue()}setReadOnly(t){this.instance.setReadOnly(t)}get isFocused(){return this.instance.isFocused()}focus(){this.instance.focus()}blur(){this.instance.blur()}getSelectionStart(){const t=this.instance.selection.getRange();return this.getIndexByRowColumn(t.start.row,t.start.column)}getSelectionEnd(){const t=this.instance.selection.getRange();return this.getIndexByRowColumn(t.end.row,t.end.column)}selectAll(){this.instance.selection.selectAll()}insertRaw(t){const e=this.instance.selection.getCursor(),s=this.instance.session.insert(e,t);this.instance.selection.setRange({start:e,end:s},!1)}setSelectionRange(t,e){this.setSelectionRangeIndices(t,e)}setPlaceHolder(t){}replaceUndoManager(){const{history:t}=this.jodit;this.instance.commands.addCommand({name:"Undo",bindKey:{win:"Ctrl-Z",mac:"Command-Z"},exec(){t.undo()}}),this.instance.commands.addCommand({name:"Redo",bindKey:{win:"Ctrl-Shift-Z",mac:"Command-Shift-Z"},exec(){t.redo()}})}}},55265(t,e,s){"use strict";s.d(e,{S(){return n}});var i=s(55186),r=s(38322),o=s(53380);class n extends o.F{constructor(){super(...arguments),this.autosize=this.j.async.debounce((()=>{this.instance.style.height="auto",this.instance.style.height=this.instance.scrollHeight+"px"}),this.j.defaultTimeout)}init(t){this.instance=t.c.element("textarea",{class:"jodit-source__mirror"}),this.container.appendChild(this.instance),t.e.on(this.instance,"mousedown keydown touchstart input",t.async.debounce(this.toWYSIWYG,t.defaultTimeout)).on("setMinHeight.source",(t=>{(0,r.A)(this.instance,"minHeight",t)})).on(this.instance,"change keydown mousedown touchstart input",this.autosize).on("afterSetMode.source",this.autosize).on(this.instance,"mousedown focus",(e=>{t.e.fire(e.type,e)})),this.autosize(),this.onReady()}destruct(){i.J.safeRemove(this.instance)}getValue(){return this.instance.value}setValue(t){this.instance.value=t}insertRaw(t){const e=this.getValue();if(0>this.getSelectionStart())this.setValue(e+t);else{const s=this.getSelectionStart(),i=this.getSelectionEnd();this.setValue(e.substring(0,s)+t+e.substring(i,e.length))}}getSelectionStart(){return this.instance.selectionStart}getSelectionEnd(){return this.instance.selectionEnd}setSelectionRange(t,e=t){this.instance.setSelectionRange(t,e)}get isFocused(){return this.instance===this.j.od.activeElement}focus(){this.instance.focus()}blur(){this.instance.blur()}setPlaceHolder(t){this.instance.setAttribute("placeholder",t)}setReadOnly(t){t?this.instance.setAttribute("readonly","true"):this.instance.removeAttribute("readonly")}selectAll(){this.instance.select()}replaceUndoManager(){const{history:t}=this.jodit;this.j.e.on(this.instance,"keydown",(e=>{if((e.ctrlKey||e.metaKey)&&"z"===e.key)return e.shiftKey?t.redo():t.undo(),this.setSelectionRange(this.getValue().length),!1}))}}},76134(t,e,s){"use strict";s.d(e,{S(){return r.S},p(){return i.p}});var i=s(5533),r=s(55265)},1992(t,e,s){"use strict";s.d(e,{b(){return o}});var i=s(65147),r=s(76134);function o(t,e,s,o,n){let a;if((0,i.isFunction)(t))a=t(e);else switch(t){case"ace":if(!e.o.shadowRoot){a=new r.p(e,s,o,n);break}default:a=new r.S(e,s,o,n)}return a.init(e),a.onReadyAlways((()=>{a.setReadOnly(e.o.readonly)})),a}},53380(t,e,s){"use strict";s.d(e,{F(){return i}});class i{constructor(t,e,s,i){this.jodit=t,this.container=e,this.toWYSIWYG=s,this.fromWYSIWYG=i,this.className="",this.isReady=!1}get j(){return this.jodit}onReady(){this.replaceUndoManager(),this.isReady=!0,this.j.e.fire(this,"ready")}onReadyAlways(t){this.isReady?t():this.j.events?.on(this,"ready",t)}}},93669(t,e,s){"use strict";var i=s(31635),r=s(17352),o=s(22664),n=s(55186),a=s(56298),l=s(65147),c=s(71005),u=(s(90722),s(1992));class d extends c.k{constructor(){super(...arguments),this.buttons=[{name:"source",group:"source"}],this.__lock=!1,this.__oldMirrorValue="",this.tempMarkerStart="{start-jodit-selection}",this.tempMarkerStartReg=/{start-jodit-selection}/g,this.tempMarkerEnd="{end-jodit-selection}",this.tempMarkerEndReg=/{end-jodit-selection}/g,this.getSelectionStart=()=>this.sourceEditor?.getSelectionStart()??0,this.getSelectionEnd=()=>this.sourceEditor?.getSelectionEnd()??0}onInsertHTML(t){if(!this.j.o.readonly&&!this.j.isEditorMode())return this.sourceEditor?.insertRaw(t),this.toWYSIWYG(),!1}fromWYSIWYG(t=!1){if(!this.__lock||!0===t){this.__lock=!0;const t=this.j.getEditorValue(!1,r.SOURCE_CONSUMER);t!==this.getMirrorValue()&&this.setMirrorValue(t),this.__lock=!1}}toWYSIWYG(){if(this.__lock)return;const t=this.getMirrorValue();t!==this.__oldMirrorValue&&(this.__lock=!0,this.j.value=t,this.__lock=!1,this.__oldMirrorValue=t)}getNormalPosition(t,e){for(e=e.replace(/<(script|style|iframe)[^>]*>[^]*?<\/\1>/im,(t=>{let e="";for(let s=0;t.length>s;s+=1)e+=r.INVISIBLE_SPACE;return e}));t>0&&e[t]===r.INVISIBLE_SPACE;)t--;let s=t;for(;s>0;){if(s--,"<"===e[s]&&void 0!==e[s+1]&&e[s+1].match(/[\w/]+/i))return s;if(">"===e[s])return t}return t}clnInv(t){return t.replace(r.INVISIBLE_SPACE_REG_EXP(),"")}onSelectAll(t){if("selectall"===t.toLowerCase()&&this.j.getRealMode()===r.MODE_SOURCE)return this.sourceEditor?.selectAll(),!1}getMirrorValue(){return this.sourceEditor?.getValue()||""}setMirrorValue(t){this.sourceEditor?.setValue(t)}setFocusToMirror(){this.sourceEditor?.focus()}saveSelection(){if(this.j.getRealMode()===r.MODE_WYSIWYG)this.j.s.save(),this.j.synchronizeValues(),this.fromWYSIWYG(!0);else{if(this.j.o.editHTMLDocumentMode)return;const t=this.getMirrorValue();if(this.getSelectionStart()===this.getSelectionEnd()){const e=this.j.s.marker(!0),s=this.getNormalPosition(this.getSelectionStart(),this.getMirrorValue());this.setMirrorValue(t.substring(0,s)+this.clnInv(e.outerHTML)+t.substring(s))}else{const e=this.j.s.marker(!0),s=this.j.s.marker(!1),i=this.getNormalPosition(this.getSelectionStart(),t),r=this.getNormalPosition(this.getSelectionEnd(),t);this.setMirrorValue(t.slice(0,i)+this.clnInv(e.outerHTML)+t.slice(i,r)+this.clnInv(s.outerHTML)+t.slice(r))}this.toWYSIWYG()}}removeSelection(){if(this.j.getRealMode()===r.MODE_WYSIWYG)return this.__lock=!0,this.j.s.restore(),void(this.__lock=!1);let t=this.getMirrorValue(),e=0,s=0;try{if(t=t.replace(/]+data-jodit-selection_marker=(["'])start\1[^>]*>[<>]*?<\/span>/gim,this.tempMarkerStart).replace(/]+data-jodit-selection_marker=(["'])end\1[^>]*>[<>]*?<\/span>/gim,this.tempMarkerEnd),!this.j.o.editHTMLDocumentMode&&this.j.o.beautifyHTML){const e=this.j.e.fire("beautifyHTML",t);(0,l.isString)(e)&&(t=e)}if(e=t.indexOf(this.tempMarkerStart),s=e,t=t.replace(this.tempMarkerStartReg,""),-1!==e){const e=t.indexOf(this.tempMarkerEnd);-1!==e&&(s=e)}t=t.replace(this.tempMarkerEndReg,"")}finally{t=t.replace(this.tempMarkerEndReg,"").replace(this.tempMarkerStartReg,"")}this.setMirrorValue(t),this.setMirrorSelectionRange(e,s),this.toWYSIWYG(),this.setFocusToMirror()}setMirrorSelectionRange(t,e){this.sourceEditor?.setSelectionRange(t,e)}onReadonlyReact(){this.sourceEditor?.setReadOnly(this.j.o.readonly)}afterInit(t){if(this.mirrorContainer=t.c.div("jodit-source"),t.workplace.appendChild(this.mirrorContainer),t.e.on("afterAddPlace changePlace afterInit",(()=>{t.workplace.appendChild(this.mirrorContainer)})),this.sourceEditor=(0,u.b)("area",t,this.mirrorContainer,this.toWYSIWYG,this.fromWYSIWYG),t.e.on(t.ow,"keydown",(t=>{t.key===r.KEY_ESC&&this.sourceEditor?.isFocused&&this.sourceEditor.blur()})),this.onReadonlyReact(),t.e.on("placeholder.source",(t=>{this.sourceEditor?.setPlaceHolder(t)})).on("change.source",this.syncValueFromWYSIWYG).on("beautifyHTML",(t=>t)),t.o.beautifyHTML){const e=()=>{if(t.isInDestruct)return!1;const e=t.ow.html_beautify;return!(!e||t.isInDestruct||(t.events?.off("beautifyHTML").on("beautifyHTML",(t=>e(t))),0))};e()||(0,l.loadNext)(t,t.o.beautifyHTMLCDNUrlsJS).then(e,(()=>null))}this.syncValueFromWYSIWYG(!0),this.initSourceEditor(t)}syncValueFromWYSIWYG(t=!1){const e=this.j;e.getMode()!==r.MODE_SPLIT&&e.getMode()!==r.MODE_SOURCE||this.fromWYSIWYG(t)}initSourceEditor(t){if("area"!==t.o.sourceEditor){const e=(0,u.b)(t.o.sourceEditor,t,this.mirrorContainer,this.toWYSIWYG,this.fromWYSIWYG);e.onReadyAlways((()=>{this.sourceEditor?.destruct(),this.sourceEditor=e,this.syncValueFromWYSIWYG(!0),t.events?.fire("sourceEditorReady",t)}))}else this.sourceEditor?.onReadyAlways((()=>{this.syncValueFromWYSIWYG(!0),t.events?.fire("sourceEditorReady",t)}))}beforeDestruct(){this.sourceEditor&&(this.sourceEditor.destruct(),delete this.sourceEditor),n.J.safeRemove(this.mirrorContainer)}}(0,i.Cg)([(0,o.watch)(":insertHTML.source")],d.prototype,"onInsertHTML",null),(0,i.Cg)([o.autobind],d.prototype,"fromWYSIWYG",null),(0,i.Cg)([o.autobind],d.prototype,"toWYSIWYG",null),(0,i.Cg)([o.autobind],d.prototype,"getNormalPosition",null),(0,i.Cg)([(0,o.watch)(":beforeCommand.source")],d.prototype,"onSelectAll",null),(0,i.Cg)([(0,o.watch)(":beforeSetMode.source")],d.prototype,"saveSelection",null),(0,i.Cg)([(0,o.watch)(":afterSetMode.source")],d.prototype,"removeSelection",null),(0,i.Cg)([o.autobind],d.prototype,"setMirrorSelectionRange",null),(0,i.Cg)([(0,o.watch)(":readonly.source")],d.prototype,"onReadonlyReact",null),(0,i.Cg)([o.autobind],d.prototype,"syncValueFromWYSIWYG",null),a.fg.add("source",d)},78703(t,e,s){"use strict";var i=s(931),r=s(49989),o=s.n(r),n=s(36115);n.T.prototype.spellcheck=!1,i.I.set("spellcheck",o()),n.T.prototype.controls.spellcheck={isActive:t=>t.o.spellcheck,icon:o(),name:"spellcheck",command:"toggleSpellcheck",tooltip:"Spellcheck"}},82602(t){"use strict";t.exports={Spellcheck:"التدقيق الإملائي"}},24575(t){"use strict";t.exports={Spellcheck:"Kontrola pravopisu"}},37414(t){"use strict";t.exports={Spellcheck:"Rechtschreibprüfung"}},82333(t){"use strict";t.exports={Spellcheck:"Corrección ortográfica"}},80124(t){"use strict";t.exports={Spellcheck:"غلطیابی املایی"}},96516(t){"use strict";t.exports={Spellcheck:"Oikeinkirjoituksen tarkistus"}},30965(t){"use strict";t.exports={Spellcheck:"Vérification Orthographique"}},80194(t){"use strict";t.exports={Spellcheck:"בדיקת איות"}},49458(t){"use strict";t.exports={Spellcheck:"Helyesírás-ellenőrzés"}},8916(t){"use strict";t.exports={Spellcheck:"Spellchecking"}},11995(t,e,s){"use strict";s.r(e),s.d(e,{ar(){return i},cs_cz(){return r},de(){return o},es(){return n},fa(){return a},fi(){return l},fr(){return c},he(){return u},hu(){return d},id(){return h},it(){return p},ja(){return m},ko(){return g},mn(){return f},nl(){return v},pl(){return b},pt_br(){return y},ru(){return _},tr(){return w},zh_cn(){return C},zh_tw(){return k}});var i=s(82602),r=s(24575),o=s(37414),n=s(82333),a=s(80124),l=s(96516),c=s(30965),u=s(80194),d=s(49458),h=s(8916),p=s(43268),m=s(11968),g=s(12715),f=s(45698),v=s(40119),b=s(92657),y=s(68648),_=s(70420),w=s(98439),C=s(55835),k=s(34747)},43268(t){"use strict";t.exports={Spellcheck:"Controllo ortografico"}},11968(t){"use strict";t.exports={Spellcheck:"スペルチェック"}},12715(t){"use strict";t.exports={Spellcheck:"맞춤법 검사"}},45698(t){"use strict";t.exports={Spellcheck:"Дүрмийн алдаа шалгах"}},40119(t){"use strict";t.exports={Spellcheck:"Spellingcontrole"}},92657(t){"use strict";t.exports={Spellcheck:"Sprawdzanie pisowni"}},68648(t){"use strict";t.exports={Spellcheck:"Verificação ortográfica"}},70420(t){"use strict";t.exports={Spellcheck:"Проверка орфографии"}},98439(t){"use strict";t.exports={Spellcheck:"Yazım denetimi"}},55835(t){"use strict";t.exports={Spellcheck:"拼写检查"}},34747(t){"use strict";t.exports={Spellcheck:"拼字檢查"}},97179(t,e,s){"use strict";var i=s(31635),r=s(22664),o=s(56298),n=s(26150),a=s(71005),l=(s(78703),s(11995));class c extends a.k{constructor(t){super(t),this.buttons=[{group:"state",name:"spellcheck"}],(0,o.JW)(l)}afterInit(t){t.e.on("afterInit afterAddPlace prepareWYSIWYGEditor",this.toggleSpellcheck),this.toggleSpellcheck(),t.registerCommand("toggleSpellcheck",(()=>{this.jodit.o.spellcheck=!this.jodit.o.spellcheck,this.toggleSpellcheck(),this.j.e.fire("updateToolbar")}))}toggleSpellcheck(){(0,n.C)(this.jodit.editor,"spellcheck",this.jodit.o.spellcheck)}beforeDestruct(t){}}(0,i.Cg)([r.autobind],c.prototype,"toggleSpellcheck",null),o.fg.add("spellcheck",c)},27195(t,e,s){"use strict";var i=s(36115);i.T.prototype.showCharsCounter=!0,i.T.prototype.countHTMLChars=!1,i.T.prototype.showWordsCounter=!0},65199(t,e,s){"use strict";var i=s(17352),r=s(55186),o=s(56298),n=s(29866);s(27195),o.fg.add("stat",class a extends n.k{constructor(){super(...arguments),this.charCounter=null,this.wordCounter=null,this.reInit=()=>{this.j.o.showCharsCounter&&this.charCounter&&this.j.statusbar.append(this.charCounter,!0),this.j.o.showWordsCounter&&this.wordCounter&&this.j.statusbar.append(this.wordCounter,!0),this.j.e.off("change keyup",this.calc).on("change keyup",this.calc),this.calc()},this.calc=this.j.async.throttle((()=>{const t=this.j.text;if(this.j.o.showCharsCounter&&this.charCounter){const e=this.j.o.countHTMLChars?this.j.value:t.replace((0,i.SPACE_REG_EXP)(),"");this.charCounter.textContent=this.j.i18n("Chars: %d",e.length)}this.j.o.showWordsCounter&&this.wordCounter&&(this.wordCounter.textContent=this.j.i18n("Words: %d",t.replace((0,i.INVISIBLE_SPACE_REG_EXP)(),"").split((0,i.SPACE_REG_EXP)()).filter((t=>t.length)).length))}),this.j.defaultTimeout)}afterInit(){this.charCounter=this.j.c.span(),this.wordCounter=this.j.c.span(),this.j.e.on("afterInit changePlace afterAddPlace",this.reInit),this.reInit()}beforeDestruct(){r.J.safeRemove(this.charCounter),r.J.safeRemove(this.wordCounter),this.j.e.off("afterInit changePlace afterAddPlace",this.reInit),this.charCounter=null,this.wordCounter=null}})},63400(t,e,s){"use strict";var i=s(36115);i.T.prototype.toolbarSticky=!0,i.T.prototype.toolbarDisableStickyForMobile=!0,i.T.prototype.toolbarStickyOffset=0},1677(t,e,s){"use strict";var i=s(31635),r=s(17352),o=s(22664),n=s(55186),a=s(56298),l=s(65147),c=s(29866);s(63400);const u=!r.IS_ES_NEXT&&r.IS_IE;class d extends c.k{constructor(){super(...arguments),this.__isToolbarStuck=!1,this.__createDummy=t=>{this.__dummyBox=this.j.c.div(),this.__dummyBox.classList.add("jodit_sticky-dummy_toolbar"),this.j.container.insertBefore(this.__dummyBox,t)},this.addSticky=t=>{this.__isToolbarStuck||(u&&!this.__dummyBox&&this.__createDummy(t),this.j.container.classList.add("jodit_sticky"),this.__isToolbarStuck=!0),(0,l.css)(t,{top:this.j.o.toolbarStickyOffset||null,width:this.j.container.offsetWidth-2}),this.__dummyBox&&(0,l.css)(this.__dummyBox,{height:t.offsetHeight})},this.removeSticky=t=>{this.__isToolbarStuck&&((0,l.css)(t,{width:"",top:""}),this.j.container.classList.remove("jodit_sticky"),this.__isToolbarStuck=!1)}}afterInit(t){t.e.on(t.ow,"scroll.sticky wheel.sticky mousewheel.sticky resize.sticky",this.__onScroll).on("getStickyState.sticky",(()=>this.__isToolbarStuck))}__onScroll(){const{jodit:t}=this;if(!t.o.toolbarSticky||!t.o.toolbar)return;const e=t.ow.pageYOffset||t.od.documentElement&&t.od.documentElement.scrollTop||0,s=(0,l.offset)(t.container,t,t.od,!0),i=t.getMode()===r.MODE_WYSIWYG&&e+t.o.toolbarStickyOffset>s.top&&s.top+s.height>e+t.o.toolbarStickyOffset&&!(t.o.toolbarDisableStickyForMobile&&this.__isMobile());if(this.__isToolbarStuck===i)return;const o=t.toolbarContainer;o&&(i?this.addSticky(o):this.removeSticky(o)),t.e.fire("toggleSticky",i)}__isMobile(){const{j:t}=this;return t&&t.options&&t.container&&t.options.sizeSM>=t.container.offsetWidth}beforeDestruct(t){n.J.safeRemove(this.__dummyBox),t.e.off(t.ow,"scroll.sticky wheel.sticky mousewheel.sticky resize.sticky",this.__onScroll).off(".sticky")}}(0,i.Cg)([(0,o.throttle)()],d.prototype,"__onScroll",null),a.fg.add("sticky",d)},61964(t,e,s){"use strict";var i=s(931),r=s(81875),o=s.n(r),n=s(36115);n.T.prototype.usePopupForSpecialCharacters=!1,n.T.prototype.specialCharacters=["!",""","#","$","%","&","'","(",")","*","+","-",".","/","0","1","2","3","4","5","6","7","8","9",":",";","<","=",">","?","@","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","[","]","^","_","`","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","{","|","}","~","€","‘","’","“","”","–","—","¡","¢","£","¤","¥","¦","§","¨","©","ª","«","»","¬","®","¯","°","²","³","´","µ","¶","·","¸","¹","º","¼","½","¾","¿","À","Á","Â","Ã","Ä","Å","Æ","Ç","È","É","Ê","Ë","Ì","Í","Î","Ï","Ð","Ñ","Ò","Ó","Ô","Õ","Ö","×","Ø","Ù","Ú","Û","Ü","Ý","Þ","ß","à","á","â","ã","ä","å","æ","ç","è","é","ê","ë","ì","í","î","ï","ð","ñ","ò","ó","ô","õ","ö","÷","ø","ù","ú","û","ü","ý","þ","ÿ","Œ","œ","Ŵ","Ŷ","ŵ","ŷ","‚","‛","„","…","™","►","•","→","⇒","⇔","♦","≈"],i.I.set("symbols",o()),n.T.prototype.controls.symbols={hotkeys:["ctrl+shift+i","cmd+shift+i"],tooltip:"Insert Special Character",popup(t,e,s){const i=t.e.fire("generateSpecialCharactersTable.symbols");if(i){if(t.o.usePopupForSpecialCharacters){const e=t.c.div();return e.classList.add("jodit-symbols"),e.appendChild(i),t.e.on(i,"close_dialog",s),e}{t.alert(i,"Select Special Character",void 0,"jodit-symbols").bindDestruct(t);const e=i.querySelector("a");e&&e.focus()}}}}},37605(t){"use strict";t.exports={symbols:"رمز"}},4726(t){"use strict";t.exports={symbols:"symbol"}},68349(t){"use strict";t.exports={symbols:"Symbol"}},88146(t){"use strict";t.exports={symbols:"Símbolo"}},11799(t){"use strict";t.exports={symbols:"سمبل"}},1311(t){"use strict";t.exports={symbols:"Symbolit"}},96282(t){"use strict";t.exports={symbols:"caractère"}},87809(t){"use strict";t.exports={symbols:"תו מיוחד"}},60817(t){"use strict";t.exports={symbols:"Szimbólum"}},48207(t){"use strict";t.exports={symbols:"simbol"}},84182(t,e,s){"use strict";s.r(e),s.d(e,{ar(){return i},cs_cz(){return r},de(){return o},es(){return n},fa(){return a},fi(){return l},fr(){return c},he(){return u},hu(){return d},id(){return h},it(){return p},ja(){return m},ko(){return g},mn(){return f},nl(){return v},pl(){return b},pt_br(){return y},ru(){return _},tr(){return w},zh_cn(){return C},zh_tw(){return k}});var i=s(37605),r=s(4726),o=s(68349),n=s(88146),a=s(11799),l=s(1311),c=s(96282),u=s(87809),d=s(60817),h=s(48207),p=s(1663),m=s(37107),g=s(73948),f=s(12333),v=s(82556),b=s(56114),y=s(47321),_=s(9407),w=s(98376),C=s(47238),k=s(72386)},1663(t){"use strict";t.exports={symbols:"Simbolo"}},37107(t){"use strict";t.exports={symbols:"symbol"}},73948(t){"use strict";t.exports={symbols:"기호"}},12333(t){"use strict";t.exports={symbols:"тэмдэгт"}},82556(t){"use strict";t.exports={symbols:"symbool"}},56114(t){"use strict";t.exports={symbols:"symbol"}},47321(t){"use strict";t.exports={symbols:"Símbolo"}},9407(t){"use strict";t.exports={symbols:"символ"}},98376(t){"use strict";t.exports={symbols:"Sembol"}},47238(t){"use strict";t.exports={symbols:"符号"}},72386(t){"use strict";t.exports={symbols:"符號"}},35541(t,e,s){"use strict";var i=s(17352),r=s(55186),o=s(56298),n=s(97369),a=s(29866),l=(s(61964),s(84182));o.fg.add("symbols",class c extends a.k{constructor(t){super(t),this.buttons=[{name:"symbols",group:"insert"}],this.countInRow=17,(0,o.JW)(l)}afterInit(t){t.e.on("generateSpecialCharactersTable.symbols",(()=>{const e=t.c.fromHTML('
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t
\n\t\t\t\t\t
'),s=e.querySelector(".jodit-symbols__preview"),o=e.querySelector("table").tBodies[0],a=[];for(let e=0;t.o.specialCharacters.length>e;){const s=t.c.element("tr");for(let i=0;this.countInRow>i&&t.o.specialCharacters.length>e;i+=1,e+=1){const r=t.c.element("td"),o=t.c.fromHTML(`${t.o.specialCharacters[e]}`);a.push(o),r.appendChild(o),s.appendChild(r)}o.appendChild(s)}const l=this;return t.e.on(a,"focus",(function(){s.innerHTML=this.innerHTML})).on(a,"mousedown",(function(e){r.J.isTag(this,"a")&&(t.s.focus(),t.s.insertHTML(this.innerHTML),t.e.fire(this,"close_dialog"),e&&e.preventDefault(),e&&e.stopImmediatePropagation())})).on(a,"mouseenter",(function(){r.J.isTag(this,"a")&&this.focus()})).on(a,"keydown",(e=>{const s=e.target;if(r.J.isTag(s,"a")){const r=parseInt((0,n.attr)(s,"-index")||"0",10),o=parseInt((0,n.attr)(s,"data-index-j")||"0",10);let c;switch(e.key){case i.KEY_UP:case i.KEY_DOWN:c=e.key===i.KEY_UP?r-l.countInRow:r+l.countInRow,void 0===a[c]&&(c=e.key===i.KEY_UP?Math.floor(a.length/l.countInRow)*l.countInRow+o:o,c>a.length-1&&(c-=l.countInRow)),a[c]&&a[c].focus();break;case i.KEY_RIGHT:case i.KEY_LEFT:c=e.key===i.KEY_LEFT?r-1:r+1,void 0===a[c]&&(c=e.key===i.KEY_LEFT?a.length-1:0),a[c]&&a[c].focus();break;case i.KEY_ENTER:t.e.fire(s,"mousedown"),e.stopImmediatePropagation(),e.preventDefault()}}})),e}))}beforeDestruct(t){t.e.off("generateSpecialCharactersTable.symbols")}})},48840(t,e,s){"use strict";s.d(e,{O(){return i.O}});var i=s(86572)},86572(t,e,s){"use strict";s.d(e,{O(){return r}});var i=s(55186);function r(t,e=!1){if(!t.o.tab.tabInsideLiInsertNewList)return!1;const[s,r]=(t=>{const e=t.createInside.fake(),s=t.createInside.fake(),i=t.s.range.cloneRange();i.collapse(!0),i.insertNode(e);const r=t.s.range.cloneRange();return r.collapse(!1),r.insertNode(s),[e,s]})(t);try{const r=((t,e,s)=>{const r=i.J.closest(e,"li",t.editor);return!!r&&!(!s&&!i.J.isLeaf(r.previousElementSibling))&&!(s&&!i.J.closest(r,"li",t.editor))&&r})(t,s,e);if(!r)return!1;if(!((t,e,s)=>{const r=i.J.closest(s,"li",e.editor);return!(!r||r!==t&&!t.contains(r))})(r,t,s))return!1;const o=i.J.closest(r,["ol","ul"],t.editor);return!(!o||e&&!i.J.closest(o,"li",t.editor)||(e?((t,e,s)=>{const r=i.J.closest(e,"li",t.editor),o=Array.from(e.children).filter((t=>i.J.isLeaf(t)));i.J.after(r,s);const n=o.indexOf(s);if(0!==n&&1!==o.length||i.J.safeRemove(e),n!==o.length-1){const t=e.cloneNode();i.J.append(s,t);for(let e=n+1;o.length>e;e+=1)i.J.append(t,o[e])}})(t,o,r):((t,e,s)=>{const r=s.previousElementSibling,o=r.lastElementChild,n=i.J.isTag(o,e.tagName)?o:t.createInside.element(e.tagName,Array.from(e.attributes).reduce(((t,e)=>(t[e.name]=e.value,t)),{}));n.appendChild(s),o!==n&&r.appendChild(n)})(t,o,r),0))}finally{const e=t.s.createRange();e.setStartAfter(s),e.setEndBefore(r),t.s.selectRange(e),i.J.safeRemove(s),i.J.safeRemove(r)}return!1}s(28712)},50974(t,e,s){"use strict";s(36115).T.prototype.tab={tabInsideLiInsertNewList:!0}},59965(t,e,s){"use strict";var i=s(31635),r=s(17352),o=s(22664),n=s(56298),a=s(71005),l=(s(50974),s(48840));class c extends a.k{afterInit(t){}__onTab(t){if(t.key===r.KEY_TAB&&this.__onShift(t.shiftKey))return!1}__onCommand(t){if(("indent"===t||"outdent"===t)&&this.__onShift("outdent"===t))return!1}__onShift(t){const e=(0,l.O)(this.j,t);return e&&this.j.e.fire("afterTab",t),e}beforeDestruct(t){}}(0,i.Cg)([(0,o.watch)(":keydown.tab")],c.prototype,"__onTab",null),(0,i.Cg)([(0,o.watch)(":beforeCommand.tab")],c.prototype,"__onCommand",null),n.fg.add("tab",c)},2533(t,e,s){"use strict";var i=s(17352),r=s(55186),o=s(56298),n=s(65147),a=s(11648);const l=new Set([i.KEY_TAB,i.KEY_LEFT,i.KEY_RIGHT,i.KEY_UP,i.KEY_DOWN]);o.fg.add("tableKeyboardNavigation",(t=>{t.e.off(".tableKeyboardNavigation").on("keydown.tableKeyboardNavigation",(e=>{const{key:s}=e;if(!l.has(s))return;const o=t.s.current();if(!o)return;const c=r.J.up(o,r.J.isCell,t.editor);if(!c)return;const{range:u}=t.s;if(s!==i.KEY_TAB&&o!==c){const t=s===i.KEY_RIGHT||s===i.KEY_DOWN,e=(0,n.call)(t?r.J.next:r.J.prev,o,(t=>s===i.KEY_UP||s===i.KEY_DOWN?r.J.isTag(t,"br"):!!t),c);if(!t&&(e||s!==i.KEY_UP&&r.J.isText(o)&&0!==u.startOffset)||t&&(e||s!==i.KEY_DOWN&&r.J.isText(o)&&o.nodeValue&&u.startOffset!==o.nodeValue.length))return}const d=t.getInstance(a.X,t.o),h=r.J.closest(c,"table",t.editor);let p=null;const m=s===i.KEY_LEFT||e.shiftKey,g=()=>(0,n.call)(m?r.J.prev:r.J.next,c,r.J.isCell,h);switch(s){case i.KEY_TAB:case i.KEY_LEFT:p=g(),p||(d.appendRow(h,!!m&&h.querySelector("tr"),!m),p=g());break;case i.KEY_UP:case i.KEY_DOWN:{const t=d.formalMatrix(h),[e,r]=d.formalCoordinate(h,c);s===i.KEY_UP?void 0!==t[e-1]&&(p=t[e-1][r]):void 0!==t[e+1]&&(p=t[e+1][r])}}if(p){if(t.e.fire("hidePopup hideResizer"),p.firstChild)s===i.KEY_TAB?t.s.select(p,!0):t.s.setCursorIn(p,s===i.KEY_RIGHT||s===i.KEY_DOWN);else{const e=t.createInside.element("br");p.appendChild(e),t.s.setCursorBefore(e)}return t.synchronizeValues(),!1}}))}))},94291(t,e,s){"use strict";var i=s(71842),r=s(65147),o=s(97369),n=s(931),a=s(67447),l=s.n(a),c=s(36115);c.T.prototype.table={selectionCellStyle:"border: 1px double #1e88e5 !important;",useExtraClassesOptions:!1},n.I.set("table",l()),c.T.prototype.controls.table={data:{cols:10,rows:10,classList:{"table table-bordered":"Bootstrap Bordered","table table-striped":"Bootstrap Striped","table table-dark":"Bootstrap Dark"}},popup(t,e,s,n){const a=n.control,l=a.data&&a.data.rows?a.data.rows:10,c=a.data&&a.data.cols?a.data.cols:10,u=t.c.fromHTML('
'+(()=>{if(!t.o.table.useExtraClassesOptions)return"";const e=[];if(a.data){const t=a.data.classList;Object.keys(t).forEach((s=>{e.push(``)}))}return e.join("")})()+'
'),d=u.querySelectorAll("span")[0],h=u.querySelectorAll("span")[1],p=u.querySelector(".jodit-form__container"),m=u.querySelector(".jodit-form__options"),g=[],f=l*c;for(let e=0;f>e;e+=1)g[e]||g.push(t.c.element("span",{dataIndex:e}));if(t.e.on(p,"mousemove",((t,e)=>{const s=t.target;if(!i.J.isTag(s,"span"))return;const r=void 0===e||isNaN(e)?parseInt((0,o.attr)(s,"-index")||"0",10):e||0,n=Math.ceil((r+1)/c),a=r%c+1;for(let t=0;g.length>t;t+=1)g[t].className=t%c+1>a||Math.ceil((t+1)/c)>n?"":"jodit_hovered";h.textContent=""+a,d.textContent=""+n})).on(p,"touchstart mousedown",(e=>{const n=e.target;if(e.preventDefault(),e.stopImmediatePropagation(),!i.J.isTag(n,"span"))return;const a=parseInt((0,o.attr)(n,"-index")||"0",10),l=Math.ceil((a+1)/c),u=a%c+1,d=t.createInside,h=d.element("tbody"),p=d.element("table");p.appendChild(h);let g,f,v=null;for(let t=1;l>=t;t+=1){g=d.element("tr");for(let t=1;u>=t;t+=1)f=d.element("td"),v||(v=f),(0,r.css)(f,"width",(100/u).toFixed(4)+"%"),f.appendChild(d.element("br")),g.appendChild(d.text("\n")),g.appendChild(d.text("\t")),g.appendChild(f);h.appendChild(d.text("\n")),h.appendChild(g)}(0,r.$$)("input[type=checkbox]:checked",m).forEach((t=>{t.value.split(/[\s]+/).forEach((t=>{p.classList.add(t)}))})),t.editor.firstChild&&t.s.insertNode(d.text("\n"),!1,!1),t.s.insertNode(p,!1),v&&(t.s.setCursorIn(v),(0,r.scrollIntoViewIfNeeded)(v,t.editor,t.ed)),s()})),n&&n.parentElement){for(let e=0;l>e;e+=1){const s=t.c.div();for(let t=0;c>t;t+=1)s.appendChild(g[e*c+t]);p.appendChild(s)}g[0]&&(g[0].className="hovered")}return u},tooltip:"Insert table"}},76385(t,e,s){"use strict";var i=s(56298);s(94291),i.fg.add("table",(t=>{t.registerButton({name:"table",group:"insert"})}))},31686(t,e,s){"use strict";var i=s(65147),r=s(35265),o=s(20703),n=s(931),a=s(16116),l=s(36339),c=s.n(l),u=s(36115);n.I.set("video",c()),u.T.prototype.controls.video={popup(t,e,s){const n=new o.XV(t,[new o.Yh(t,[new o.tS(t,{name:"url",required:!0,label:"URL",placeholder:"https://",validators:["url"]})]),new o.Yh(t,[(0,r.$n)(t,"","Insert","primary").onAction((()=>n.submit()))])]),l=new o.XV(t,[new o.Yh(t,[new o.F0(t,{name:"code",required:!0,label:"Embed code"})]),new o.Yh(t,[(0,r.$n)(t,"","Insert","primary").onAction((()=>l.submit()))])]),c=[],u=e=>{t.s.restore(),t.s.insertHTML(e),s()};return t.s.save(),c.push({icon:"link",name:"Link",content:n.container},{icon:"source",name:"Code",content:l.container}),n.onSubmit((t=>{u((0,i.convertMediaUrlToVideoEmbed)(t.url))})),l.onSubmit((t=>{u(t.code)})),(0,a.Zg)(t,c)},tags:["iframe"],tooltip:"Insert youtube/vimeo video"}},38309(t,e,s){"use strict";var i=s(56298);s(31686),i.fg.add("video",(t=>{t.registerButton({name:"video",group:"media"})}))},2805(t,e,s){"use strict";s(36115).T.prototype.wrapNodes={exclude:new Set(["hr","style","br"]),emptyBlockAfterInit:!0}},14367(t,e,s){"use strict";var i=s(31635),r=s(22664),o=s(71842),n=s(56298),a=s(98253),l=s(71005);s(2805);class c extends l.k{constructor(){super(...arguments),this.isSuitableStart=t=>o.J.isText(t)&&(0,a.K)(t.nodeValue)&&(/[^\s]/.test(t.nodeValue)||t.parentNode?.firstChild===t&&this.isSuitable(t.nextSibling))||this.isNotWrapped(t)&&!o.J.isTemporary(t),this.isSuitable=t=>o.J.isText(t)||this.isNotWrapped(t),this.isNotWrapped=t=>o.J.isElement(t)&&!(o.J.isBlock(t)||o.J.isTag(t,this.j.o.wrapNodes.exclude))}afterInit(t){"br"!==t.o.enter.toLowerCase()&&t.e.on("drop.wtn focus.wtn keydown.wtn mousedown.wtn afterInit.wtn backSpaceAfterDelete.wtn",this.preprocessInput,{top:!0}).on("afterInit.wtn postProcessSetEditorValue.wtn afterCommitStyle.wtn backSpaceAfterDelete.wtn",this.postProcessSetEditorValue)}beforeDestruct(t){t.e.off(".wtn")}postProcessSetEditorValue(){const{jodit:t}=this;if(!t.isEditorMode())return;let e=t.editor.firstChild,s=!1;for(;e;){if(e=u(e,t),this.isSuitableStart(e)){s||t.s.save(),s=!0;const i=t.createInside.element(t.o.enter);for(o.J.before(e,i);e&&this.isSuitable(e);){const t=e.nextSibling;i.appendChild(e),e=t}i.normalize(),e=i}e=e&&e.nextSibling}s&&(t.s.restore(),"afterInit"===t.e.current&&t.e.fire("internalChange"))}preprocessInput(){const{jodit:t}=this,e="afterInit"===t.e.current;if(!t.isEditorMode()||t.editor.firstChild||!t.o.wrapNodes.emptyBlockAfterInit&&e)return;const s=t.createInside.element(t.o.enter),i=t.createInside.element("br");o.J.append(s,i),o.J.append(t.editor,s),t.s.isFocused()&&t.s.setCursorBefore(i),t.e.fire("internalChange")}}function u(t,e){let s=t,i=t;do{if(!o.J.isElement(i)||!o.J.isLeaf(i)||o.J.isList(i.parentElement))break;{const t=o.J.findNotEmptySibling(i,!1);o.J.isTag(s,"ul")?s.appendChild(i):s=o.J.wrap(i,"ul",e.createInside),i=t}}while(i);return s}(0,i.Cg)([r.autobind],c.prototype,"postProcessSetEditorValue",null),(0,i.Cg)([r.autobind],c.prototype,"preprocessInput",null),n.fg.add("wrapNodes",c)},88850(t,e,s){"use strict";s(36115).T.prototype.showXPathInStatusbar=!0},36133(t,e,s){"use strict";var i=s(17352),r=s(71842),o=s(56298),n=s(65147),a=s(71005),l=s(34248),c=s(8809);s(88850),o.fg.add("xpath",class u extends a.k{constructor(){super(...arguments),this.onContext=(t,e)=>(this.menu||(this.menu=new l.t(this.j)),this.menu.show(e.clientX,e.clientY,[{icon:"bin",title:t===this.j.editor?"Clear":"Remove",exec:()=>{t!==this.j.editor?r.J.safeRemove(t):this.j.value="",this.j.synchronizeValues()}},{icon:"select-all",title:"Select",exec:()=>{this.j.s.select(t)}}]),!1),this.onSelectPath=(t,e)=>{this.j.s.focus();const s=(0,n.attr)(e.target,"-path")||"/";if("/"===s)return this.j.execCommand("selectall"),!1;try{const t=this.j.ed.evaluate(s,this.j.editor,null,XPathResult.ANY_TYPE,null).iterateNext();if(t)return this.j.s.select(t),!1}catch{}return this.j.s.select(t),!1},this.tpl=(t,e,s,i)=>{const r=this.j.c.fromHTML(`${(0,n.trim)(s)}`),o=r.firstChild;return this.j.e.on(o,"click",this.onSelectPath.bind(this,t)).on(o,"contextmenu",this.onContext.bind(this,t)),r},this.removeSelectAll=()=>{this.selectAllButton&&(this.selectAllButton.destruct(),delete this.selectAllButton)},this.appendSelectAll=()=>{this.removeSelectAll(),this.selectAllButton=(0,c.BJ)(this.j,{name:"selectall",...this.j.o.controls.selectall}),this.selectAllButton.state.size="tiny",this.container&&this.container.insertBefore(this.selectAllButton.container,this.container.firstChild)},this.calcPathImd=()=>{if(this.isDestructed)return;const t=this.j.s.current();if(this.container&&(this.container.innerHTML=i.INVISIBLE_SPACE),t){let e,s,i;r.J.up(t,(t=>{!t||this.j.editor===t||r.J.isText(t)||r.J.isComment(t)||(e=t.nodeName.toLowerCase(),s=(0,n.getXPathByElement)(t,this.j.editor).replace(/^\//,""),i=this.tpl(t,s,e,this.j.i18n("Select %s",e)),this.container&&this.container.insertBefore(i,this.container.firstChild))}),this.j.editor)}this.appendSelectAll()},this.calcPath=this.j.async.debounce(this.calcPathImd,2*this.j.defaultTimeout)}afterInit(){this.j.o.showXPathInStatusbar&&(this.container=this.j.c.div("jodit-xpath"),this.j.e.off(".xpath").on("mouseup.xpath change.xpath keydown.xpath changeSelection.xpath",this.calcPath).on("afterSetMode.xpath afterInit.xpath changePlace.xpath",(()=>{this.j.o.showXPathInStatusbar&&this.container&&(this.j.statusbar.append(this.container),this.j.getRealMode()===i.MODE_WYSIWYG?this.calcPath():(this.container&&(this.container.innerHTML=i.INVISIBLE_SPACE),this.appendSelectAll()))})),this.calcPath())}beforeDestruct(){this.j&&this.j.events&&this.j.e.off(".xpath"),this.removeSelectAll(),this.menu&&this.menu.destruct(),r.J.safeRemove(this.container),delete this.menu,delete this.container}})},79721(t,e,s){"use strict";s.r(e),s.d(e,{angle_down(){return r.a},angle_left(){return n.a},angle_right(){return l.a},angle_up(){return u.a},bin(){return h.a},cancel(){return m.a},center(){return f.a},check(){return b.a},chevron(){return _.a},dots(){return C.a},eye(){return S.a},file(){return E.a},folder(){return I.a},info_circle(){return z.a},left(){return A.a},lock(){return P.a},ok(){return N.a},pencil(){return D.a},plus(){return O.a},resize_handler(){return H.a},right(){return V.a},save(){return $.a},settings(){return K.a},unlock(){return G.a},update(){return Z.a},upload(){return tt.a},valign(){return st.a}});var i=s(88497),r=s.n(i),o=s(91882),n=s.n(o),a=s(14305),l=s.n(a),c=s(58446),u=s.n(c),d=s(39858),h=s.n(d),p=s(70881),m=s.n(p),g=s(60636),f=s.n(g),v=s(32013),b=s.n(v),y=s(45512),_=s.n(y),w=s(80347),C=s.n(w),k=s(95134),S=s.n(k),T=s(70697),E=s.n(T),x=s(49983),I=s.n(x),j=s(98964),z=s.n(j),L=s(8136),A=s.n(L),M=s(94806),P=s.n(M),R=s(31365),N=s.n(R),B=s(44636),D=s.n(B),q=s(36327),O=s.n(q),J=s(53328),H=s.n(J),F=s(98711),V=s.n(F),W=s(53808),$=s.n(W),U=s(20784),K=s.n(U),Y=s(70999),G=s.n(Y),X=s(45244),Z=s.n(X),Q=s(99876),tt=s.n(Q),et=s(14006),st=s.n(et)},57741(t){t.exports.default=["إبدأ في الكتابة...","حول جوديت","محرر جوديت","دليل مستخدم جوديت","يحتوي على مساعدة مفصلة للاستخدام","للحصول على معلومات حول الترخيص، يرجى الذهاب لموقعنا:","شراء النسخة الكاملة","حقوق الطبع والنشر © XDSoft.net - Chupurnov Valeriy. كل الحقوق محفوظة.","مِرْساة","فتح في نافذة جديدة","فتح المحرر في الحجم الكامل","مسح التنسيق","ملء اللون أو تعيين لون النص","إعادة","تراجع","عريض","مائل","إدراج قائمة غير مرتبة","إدراج قائمة مرتبة","محاذاة للوسط","محاذاة مثبتة","محاذاة لليسار","محاذاة لليمين","إدراج خط أفقي","إدراج صورة","ادخال الملف","إدراج فيديو يوتيوب/فيميو ","إدراج رابط","حجم الخط","نوع الخط","إدراج كتلة تنسيق","عادي","عنوان 1","عنوان 2","عنوان 3","عنوان 4","إقتباس","كود","إدراج","إدراج جدول","تقليل المسافة البادئة","زيادة المسافة البادئة","تحديد أحرف خاصة","إدراج حرف خاص","تنسيق الرسم","تغيير الوضع","هوامش","أعلى","يمين","أسفل","يسار","الأنماط","الطبقات","محاذاة","اليمين","الوسط","اليسار","--غير مضبوط--","Src","العنوان","العنوان البديل","الرابط","افتح الرابط في نافذة جديدة","الصورة","ملف","متقدم","خصائص الصورة","إلغاء","حسنا","متصفح الملفات","حدث خطأ في تحميل القائمة ","حدث خطأ في تحميل المجلدات","هل أنت واثق؟","أدخل اسم المجلد","إنشاء مجلد","أكتب إسم","إسقاط صورة","إسقاط الملف","أو أنقر","النص البديل","رفع","تصفح","الخلفية","نص","أعلى","الوسط","الأسفل","إدراج عمود قبل","إدراج عمود بعد","إدراج صف أعلى","إدراج صف أسفل","حذف الجدول","حذف الصف","حذف العمود","خلية فارغة","%d حرف","%d كلام","اضرب من خلال","أكد","حرف فوقي","مخطوطة","قطع الاختيار","اختر الكل","استراحة","البحث عن","استبدل ب","محل","معجون","اختر محتوى للصق","مصدر","بالخط العريض","مائل","شغل","صلة","إلغاء","كرر","طاولة","صورة","نظيف","فقرة","حجم الخط","فيديو","الخط","حول المحرر","طباعة","أكد","شطب","المسافة البادئة","نتوء","ملء الشاشة","الحجم التقليدي","الخط","قائمة","قائمة مرقمة","قطع","اختر الكل","قانون","فتح الرابط","تعديل الرابط","سمة Nofollow","إزالة الرابط","تحديث","لتحرير","مراجعة","URL","تحرير","محاذاة أفقية","فلتر","عن طريق التغيير","بالاسم","حسب الحجم","إضافة مجلد","إعادة","احتفظ","حفظ باسم","تغيير الحجم","حجم القطع","عرض","ارتفاع","حافظ على النسب","أن","لا","حذف","تميز","تميز %s","محاذاة عمودية","انشق، مزق","اذهب","أضف العمود","اضف سطر","رخصة %s","حذف","انقسام عمودي","تقسيم أفقي","الحدود","يشبه الكود الخاص بك HTML. تبقي كما HTML؟","الصق ك HTML","احتفظ","إدراج كنص","إدراج النص فقط","يمكنك فقط تحرير صورك الخاصة. تحميل هذه الصورة على المضيف؟","تم تحميل الصورة بنجاح على الخادم!","لوحة","لا توجد ملفات في هذا الدليل.","إعادة تسمية","أدخل اسم جديد","معاينة","تحميل","لصق من الحافظة","متصفحك لا يدعم إمكانية الوصول المباشر إلى الحافظة.","نسخ التحديد","نسخ","دائرة نصف قطرها الحدود","عرض كل","تطبيق","يرجى ملء هذا المجال","يرجى إدخال عنوان ويب","الافتراضي","دائرة","نقطة","المربعة","البحث","تجد السابقة","تجد التالي","للصق المحتوى قادم من Microsoft Word/Excel الوثيقة. هل تريد أن تبقي شكل أو تنظيفه ؟ ","كلمة لصق الكشف عن","نظيفة","أدخل اسم الفصل","اضغط البديل لتغيير حجم مخصص"]},56014(t){t.exports.default=["Napiš něco","O Jodit","Editor Jodit","Jodit Uživatelská příručka","obsahuje detailní nápovědu","Pro informace o licenci, prosím, přejděte na naši stránku:","Koupit plnou verzi","Copyright © XDSoft.net - Chupurnov Valeriy. Všechna práva vyhrazena.","Anchor","Otevřít v nové záložce","Otevřít v celoobrazovkovém režimu","Vyčistit formátování","Barva výplně a písma","Vpřed","Zpět","Tučné","Kurzíva","Odrážky","Číslovaný seznam","Zarovnat na střed","Zarovnat do bloku","Zarovnat vlevo","Zarovnat vpravo","Vložit horizontální linku","Vložit obrázek","Vložit soubor","Vložit video (YT/Vimeo)","Vložit odkaz","Velikost písma","Typ písma","Formátovat blok","Normální text","Nadpis 1","Nadpis 2","Nadpis 3","Nadpis 4","Citát","Kód","Vložit","Vložit tabulku","Zmenšit odsazení","Zvětšit odsazení","Vybrat speciální symbol","Vložit speciální symbol","Použít formát","Změnit mód","Okraje","horní","pravý","spodní","levý","Styly","Třídy","Zarovnání","Vpravo","Na střed","Vlevo","--nenastaveno--","src","Titulek","Alternativní text (alt)","Link","Otevřít link v nové záložce","Obrázek","soubor","Rozšířené","Vlastnosti obrázku","Zpět","Ok","Prohlížeč souborů","Chyba při načítání seznamu souborů","Chyba při načítání složek","Jste si jistý(á)?","Název složky","Vytvořit složku","název","Přetáhněte sem obrázek","Přetáhněte sem soubor","nebo klikněte","Alternativní text","Nahrát","Server","Pozadí","Text","Nahoru","Na střed","Dolu","Vložit sloupec před","Vložit sloupec za","Vložit řádek nad","Vložit řádek pod","Vymazat tabulku","Vymazat řádku","Vymazat sloupec","Vyčistit buňku","Znaky: %d","Slova: %d","Přeškrtnuto","Podtrženo","Horní index","Dolní index","Vyjmout označené","Označit vše","Zalomení","Najdi","Nahradit za","Vyměňte","Vložit","Vyber obsah pro vložení","HTML","tučně","kurzíva","štětec","odkaz","zpět","vpřed","tabulka","obrázek","guma","odstavec","velikost písma","video","písmo","о editoru","tisk","podtrženo","přeškrtnuto","zvětšit odsazení","zmenšit odsazení","celoobrazovkový režim","smrsknout","Linka","Odrážka","Číslovaný seznam","Vyjmout","Označit vše","Kód","Otevřít odkaz","Upravit odkaz","Atribut no-follow","Odstranit odkaz","Aktualizovat","Chcete-li upravit","Zobrazit","URL","Editovat","Horizontální zarovnání","Filtr","Dle poslední změny","Dle názvu","Dle velikosti","Přidat složku","Reset","Uložit","Uložit jako...","Změnit rozměr","Ořezat","Šířka","Výška","Ponechat poměr","Ano","Ne","Vyjmout","Označit","Označit %s","Vertikální zarovnání","Rozdělit","Spojit","Přidat sloupec","Přidat řádek","Licence: %s","Vymazat","Rozdělit vertikálně","Rozdělit horizontálně","Okraj","Váš text se podobá HTML. Vložit ho jako HTML?","Vložit jako HTML","Ponechat originál","Vložit jako TEXT","Vložit pouze TEXT","Můžete upravovat pouze své obrázky. Načíst obrázek?","Obrázek byl úspěšně nahrán!","paleta","V tomto adresáři nejsou žádné soubory.","přejmenovat","Zadejte nový název","náhled","Stažení","Vložit ze schránky","Váš prohlížeč nepodporuje přímý přístup do schránky.","Kopírovat výběr","kopírování","Border radius","Zobrazit všechny","Platí","Prosím, vyplňte toto pole","Prosím, zadejte webovou adresu","Výchozí","Kruh","Dot","Quadrate","Najít","Najít Předchozí","Najít Další","Obsah, který vkládáte, je pravděpodobně z Microsoft Word / Excel. Chcete ponechat formát nebo vložit pouze text?","Detekován fragment z Wordu nebo Excelu","Vyčistit","Vložte název třídy","Stiskněte Alt pro vlastní změnu velikosti"]},95461(t){t.exports.default=["Bitte geben Sie einen Text ein","Über Jodit","Jodit Editor","Das Jodit Benutzerhandbuch","beinhaltet ausführliche Informationen wie Sie den Editor verwenden können.","Für Informationen zur Lizenz, besuchen Sie bitte unsere Web-Präsenz:","Vollversion kaufen","Copyright © XDSoft.net - Chupurnov Valeriy. Alle Rechte vorbehalten.","Anker","In neuer Registerkarte öffnen","Editor in voller Größe öffnen","Formatierung löschen","Füllfarbe oder Textfarbe ändern","Wiederholen","Rückgängig machen","Fett","Kursiv","Unsortierte Liste einfügen","Nummerierte Liste einfügen","Mittig ausrichten","Blocksatz","Links ausrichten","Rechts ausrichten","Horizontale Linie einfügen","Bild einfügen","Datei einfügen","Youtube/vimeo Video einfügen","Link einfügen","Schriftgröße","Schriftfamilie","Formatblock einfügen","Normal","Überschrift 1","Überschrift 2","Überschrift 3","Überschrift 4","Zitat","Code","Einfügen","Tabelle einfügen","Einzug verkleinern","Einzug vergrößern","Sonderzeichen auswählen","Sonderzeichen einfügen","Format kopieren","Änderungsmodus","Ränder","Oben","Rechts","Unten","Links","CSS Stil","CSS Klassen","Ausrichtung","Rechts","Zentriert","Links","Keine","Pfad","Titel","Alternativer Text","Link","Link in neuem Tab öffnen","Bild","Datei","Fortgeschritten","Bildeigenschaften","Abbrechen","OK","Dateibrowser","Fehler beim Laden der Liste","Fehler beim Laden der Ordner","Sind Sie sicher?","Geben Sie den Verzeichnisnamen ein","Verzeichnis erstellen","Typname","Bild hier hinziehen","Datei löschen","oder hier klicken","Alternativtext","Hochladen","Auswählen","Hintergrund","Text","Oben","Mittig","Unten","Spalte davor einfügen","Spalte danach einfügen","Zeile oberhalb einfügen","Zeile unterhalb einfügen","Tabelle löschen","Zeile löschen","Spalte löschen","Zelle leeren","Zeichen: %d","Wörter: %d","Durchstreichen","Unterstreichen","Hochstellen","Tiefstellen","Auswahl ausschneiden","Alles markieren","Pause","Suche nach","Ersetzen durch","Ersetzen","Einfügen","Wählen Sie den Inhalt zum Einfügen aus","HTML","Fett gedruckt","Kursiv","Bürste","Verknüpfung","Rückgängig machen","Wiederholen","Tabelle","Bild","Radiergummi","Absatz","Schriftgröße","Video","Schriftart","Über","Drucken","Unterstreichen","Durchstreichen","Einzug","Herausstellen","Vollgröße","Schrumpfen","die Linie","Liste von","Nummerierte Liste","Schneiden","Wählen Sie Alle aus","Code einbetten","Link öffnen","Link bearbeiten","Nofollow-Attribut","Link entfernen","Aktualisieren","Bearbeiten","Ansehen","URL","Bearbeiten","Horizontale Ausrichtung","Filter","Sortieren nach geändert","Nach Name sortieren","Nach Größe sortiert","Ordner hinzufügen","Wiederherstellen","Speichern","Speichern als","Größe ändern","Größe anpassen","Breite","Höhe","Seitenverhältnis beibehalten","Ja","Nein","Entfernen","Markieren","Markieren: %s","Vertikale Ausrichtung","Unterteilen","Vereinen","Spalte hinzufügen","Zeile hinzufügen",null,"Löschen","Vertikal unterteilen","Horizontal unterteilen","Rand","Ihr Text ähnelt HTML-Code. Als HTML beibehalten?","Als HTML einfügen?","Original speichern","Als Text einfügen","Nur Text einfügen","Sie können nur Ihre eigenen Bilder bearbeiten. Dieses Bild auf den Host herunterladen?","Das Bild wurde erfolgreich auf den Server hochgeladen!","Palette","In diesem Verzeichnis befinden sich keine Dateien.","Umbenennen","Geben Sie einen neuen Namen ein","Vorschau","Herunterladen","Aus Zwischenablage einfügen","Ihr Browser unterstützt keinen direkten Zugriff auf die Zwischenablage.","Auswahl kopieren","Kopieren","Radius für abgerundete Ecken","Alle anzeigen","Anwenden","Bitte füllen Sie dieses Feld aus","Bitte geben Sie eine Web-Adresse ein","Standard","Kreis","Punkte","Quadrate","Suchen","Suche vorherige","Weitersuchen","Der Inhalt, den Sie einfügen, stammt aus einem Microsoft Word / Excel-Dokument. Möchten Sie das Format erhalten oder bereinigen?","In Word formatierter Text erkannt","Säubern","className (CSS) einfügen","Drücken Sie Alt für benutzerdefinierte Größenanpassung"]},63837(t){t.exports.default={"Type something":"Start writing...",pencil:"Edit",Quadrate:"Square"}},39386(t){t.exports.default=["Escriba algo...","Acerca de Jodit","Jodit Editor","Guía de usuario Jodit","contiene ayuda detallada para el uso.","Para información sobre la licencia, por favor visite nuestro sitio:","Compre la versión completa","Copyright © XDSoft.net - Chupurnov Valeriy. Todos los derechos reservados.","Anclar","Abrir en nueva pestaña","Abrir editor en pantalla completa","Limpiar formato","Color de relleno o de letra","Rehacer","Deshacer","Negrita","Cursiva","Insertar lista no ordenada","Insertar lista ordenada","Alinear Centrado","Alinear Justificado","Alinear Izquierda","Alinear Derecha","Insertar línea horizontal","Insertar imagen","Insertar archivo","Insertar video de Youtube/vimeo","Insertar vínculo","Tamaño de letra","Familia de letra","Insertar bloque","Normal","Encabezado 1","Encabezado 2","Encabezado 3","Encabezado 4","Cita","Código","Insertar","Insertar tabla","Disminuir sangría","Aumentar sangría","Seleccionar caracter especial","Insertar caracter especial","Copiar formato","Cambiar modo","Márgenes","arriba","derecha","abajo","izquierda","Estilos CSS","Clases CSS","Alinear","Derecha","Centrado","Izquierda","--No Establecido--","Fuente","Título","Texto Alternativo","Vínculo","Abrir vínculo en nueva pestaña","Imagen","Archivo","Avanzado","Propiedades de imagen","Cancelar","Aceptar","Buscar archivo","Error al cargar la lista","Error al cargar las carpetas","¿Está seguro?","Entre nombre de carpeta","Crear carpeta","Entre el nombre","Soltar imagen","Soltar archivo","o click","Texto alternativo","Subir","Buscar","Fondo","Texto","Arriba","Centro","Abajo","Insertar columna antes","Interar columna después","Insertar fila arriba","Insertar fila debajo","Borrar tabla","Borrar fila","Borrar columna","Vaciar celda","Caracteres: %d","Palabras: %d","Tachado","Subrayado","superíndice","subíndice","Cortar selección","Seleccionar todo","Pausa","Buscar","Reemplazar con","Reemplazar","Pegar","Seleccionar contenido para pegar","HTML","negrita","cursiva","Brocha","Vínculo","deshacer","rehacer","Tabla","Imagen","Borrar","Párrafo","Tamaño de letra","Video","Letra","Acerca de","Imprimir","subrayar","tachar","sangría","quitar sangría","Tamaño completo","encoger","línea horizontal","lista sin ordenar","lista ordenada","Cortar","Seleccionar todo","Incluir código","Abrir vínculo","Editar vínculo","No seguir","Desvincular","Actualizar","Para editar","Ver","URL","Editar","Alineación horizontal","Filtrar","Ordenar por fecha modificación","Ordenar por nombre","Ordenar por tamaño","Agregar carpeta","Resetear","Guardar","Guardar como...","Redimensionar","Recortar","Ancho","Alto","Mantener relación de aspecto","Si","No","Quitar","Seleccionar","Seleccionar: %s","Alineación vertical","Dividir","Mezclar","Agregar columna","Agregar fila",null,"Borrar","Dividir vertical","Dividir horizontal","Borde","El código es similar a HTML. ¿Mantener como HTML?","Pegar como HTML?","Mantener","Insertar como texto","Insertar solo texto","Solo puedes editar tus propias imágenes. ¿Descargar esta imagen en el servidor?","¡La imagen se ha subido correctamente al servidor!","paleta","No hay archivos en este directorio.","renombrar","Ingresa un nuevo nombre","avance","Descargar","Pegar desde el portapapeles","Su navegador no soporta el acceso directo en el portapapeles.","Selección de copia","copia","Radio frontera","Mostrar todos los","Aplicar","Por favor, rellene este campo","Por favor, introduzca una dirección web","Predeterminado","Círculo","Punto","Cuadro","Encontrar","Buscar Anterior","Buscar Siguiente","El contenido pegado proviene de un documento de Microsoft Word/Excel. ¿Desea mantener el formato o limpiarlo?","Pegado desde Word detectado","Limpiar","Insertar nombre de clase","Presione Alt para cambiar el tamaño personalizado"]},62327(t){t.exports.default=["Kirjoita jotain...","Tietoja Jodit:ista","Jodit Editor","Jodit käyttäjän ohje","sisältää tarkempaa tietoa käyttämiseen","Tietoa lisensoinnista, vieraile verkkosivuillamme:","Osta täysi versio","Copyright © XDSoft.net - Chupurnov Valeriy. Kaikki oikeudet pidätetään.","Ankkuri","Avaa uudessa välilehdessä","Avaa täysikokoisena","Poista muotoilu","Täytä värillä tai aseta tekstin väri","Tee uudelleen","Peruuta","Lihavoitu","Kursiivi","Lisää järjestämätön lista","Lisää järjestetty lista","Asemoi keskelle","Asemoi tasavälein","Asemoi vasemmalle","Asemoi oikealle","Lisää vaakasuuntainen viiva","Lisää kuva","Lisää tiedosto","Lisää Youtube-/vimeo- video","Lisää linkki","Kirjasimen koko","Kirjasimen nimi","Lisää muotoilualue","Normaali","Otsikko 1","Otsikko 2","Otsikko 3","Otsikko 4","Lainaus","Koodi","Lisää","Lisää taulukko","Pienennä sisennystä","Lisää sisennystä","Valitse erikoismerkki","Lisää erikoismerkki","Maalaa muotoilu","Vaihda tilaa","Marginaalit","ylös","oikealle","alas","vasemmalle","CSS-tyylit","CSS-luokat","Asemointi","Oikea","Keskellä","Vasen","--Ei asetettu--","Fuente","Otsikko","Vaihtoehtoinen teksti","Linkki","Avaa uudessa välilehdessä","Kuva","Tiedosto","Avanzado","Kuvan ominaisuudet","Peruuta","Ok","Tiedostoselain","Virhe listan latauksessa","Virhe kansioiden latauksessa","Oletko varma?","Syötä hakemiston nimi","Luo hakemisto","Syötä nimi","Pudota kuva","Pudota tiedosto","tai klikkaa","Vaihtoehtoinen teksti","Lataa","Selaa","Tausta","Teksti","Ylös","Keskelle","Alas","Lisää sarake ennen","Lisää sarake jälkeen","Lisää rivi ylös","Lisää rivi alle","Poista taulukko","Poista rivi","Poista sarake","Tyhjennä solu","Merkit: %d","Sanat: %d","Yliviivaus","Alleviivaus","yläviite","alaviite","Leikkaa valinta","Valitse kaikki","Vaihto","Etsi arvoa","Korvaa arvolla","Korvaa","Liitä","Valitse liitettävä sisältö","HTML","lihavoitu","kursiivi","sivellin","linkki","peruuta","tee uudelleen","taulukko","kuva","pyyhekumi","kappale","tekstin koko","video","kirjasin","tietoja","tulosta","alleviivaa","yliviivaa","sisennä","pienennä sisennystä","täysikokoinen","pienennä","vaakaviiva","järjestetty lista","järjestämätön lista","leikkaa","valitse kaikki","Sisällytä koodi","Avaa linkki","Muokkaa linkkiä","Älä seuraa","Pura linkki","Päivitä","Muokkaa","Ver","URL","Muokkaa","Vaaka-asemointi","Suodatin","Järjestä muuttuneilla","Järjestä nimellä","Järjestä koolla","Lisää kansio","Nollaa","Tallenna","Tallenna nimellä ...","Muuta kokoa","Rajaa","Leveys","Korkeus","Säilytä kuvasuhde","Kyllä","Ei","Poista","Valitse","Valitse: %s","Pystyasemointi","Jaa","Yhdistä","Lisää sarake","Lisää rivi",null,"Poista","Jaa pystysuuntaisesti","Jaa vaakasuuntaisesti","Reuna","Koodi on HTML:n tapaista. Säilytetäänkö HTML?","Liitä HTML:nä?","Säilytä","Lisää tekstinä","Lisää vain teksti","Voit muokata vain omia kuvia. Lataa tämä kuva palvelimelle?","Kuva on onnistuneesti ladattu palvelimelle!","paletti","Tiedostoja ei ole","Nimeä uudelleen","Syötä uusi nimi","esikatselu","Lataa","Liitä leikepöydältä","Selaimesi ei tue suoraa pääsyä leikepöydälle.","Kopioi valinta","kopioi","Reunan pyöristys","Näytä kaikki","Käytä","Täytä tämä kenttä","Annan web-osoite","Oletus","Ympyrä","Piste","Neliö","Hae","Hae edellinen","Hae seuraava","Liitetty sisältö tulee Microsoft Word-/Excel- tiedostosta. Haluatko säilyttää muotoilun vai poistaa sen?","Word liittäminen havaittu","Tyhjennä","Lisää luokkanimi","Paina Alt muokattuun koon muuttamiseen"]},25090(t){t.exports.default=["Ecrivez ici","A propos de Jodit","Editeur Jodit","Guide de l'utilisateur","Aide détaillée à l'utilisation","Consulter la licence sur notre site web:","Acheter la version complète","Copyright © XDSoft.net - Chupurnov Valeriy. Tous droits réservés.","Ancre","Ouvrir dans un nouvel onglet","Ouvrir l'éditeur en pleine page","Supprimer le formattage","Modifier la couleur du fond ou du texte","Refaire","Défaire","Gras","Italique","Liste non ordonnée","Liste ordonnée","Centrer","Justifier","Aligner à gauche ","Aligner à droite","Insérer une ligne horizontale","Insérer une image","Insérer un fichier","Insérer une vidéo","Insérer un lien","Taille des caractères","Famille des caractères","Bloc formatté","Normal","Titre 1","Titre 2","Titre 3","Titre 4","Citation","Code","Insérer","Insérer un tableau","Diminuer le retrait","Retrait plus","Sélectionnez un caractère spécial","Insérer un caractère spécial","Cloner le format","Mode wysiwyg <-> code html","Marges","haut","droite","Bas","gauche","Styles","Classes","Alignement","Droite","Centre","Gauche","--Non disponible--","Source","Titre","Alternative","Lien","Ouvrir le lien dans un nouvel onglet","Image","fichier","Avancé","Propriétés de l'image","Annuler","OK","Explorateur de fichiers","Erreur de liste de chargement","Erreur de dossier de chargement","Etes-vous sûrs ?","Entrer le nom de dossier","Créer un dossier","type de fichier","Coller une image","Déposer un fichier","ou cliquer","Texte de remplacemement","Charger","Chercher","Arrière-plan","Texte","Haut","Milieu","Bas","Insérer une colonne avant","Insérer une colonne après","Insérer une ligne au dessus","Insérer une ligne en dessous","Supprimer le tableau","Supprimer la ligne","Supprimer la colonne","Vider la cellule","Symboles: %d","Mots: %d","Barrer","Souligner","exposant","indice","Couper la sélection","Tout sélectionner","Pause","Rechercher","Remplacer par","Remplacer","Coller","Choisissez le contenu à coller","la source","gras","italique","pinceau","lien","annuler","refaire","tableau","image","gomme","clause","taille de police","Video","police","à propos de l'éditeur","impression","souligné","barré","indentation","retrait","taille réelle","taille conventionnelle","la ligne","Liste","Liste numérotée","Couper","Sélectionner tout",null,"Ouvrir le lien","Modifier le lien","Attribut Nofollow","Supprimer le lien","Mettre à jour","Pour éditer","Voir","URL",null,"Alignement horizontal","Filtre","Trier par modification","Trier par nom","Trier par taille","Créer le dossier","Restaurer","Sauvegarder","Enregistrer sous","Changer la taille","Taille de garniture","Largeur","Hauteur","Garder les proportions","Oui","Non","Supprimer","Mettre en évidence","Mettre en évidence: %s","Alignement vertical","Split","aller","Ajouter une colonne","Ajouter une rangée",null,"Effacer","Split vertical","Split horizontal","Bordure","Votre texte que vous essayez de coller est similaire au HTML. Collez-le en HTML?","Coller en HTML?","Sauvegarder l'original","Coller en tant que texte","Coller le texte seulement","Vous ne pouvez éditer que vos propres images. Téléchargez cette image sur l'hôte?","L'image a été téléchargée avec succès sur le serveur!","Palette","Il n'y a aucun fichier dans ce répertoire.","renommer","Entrez un nouveau nom","Aperçu","Télécharger","Coller à partir du presse-papiers","Votre navigateur ne prend pas en charge l'accès direct au presse-papiers.","Copier la sélection","copie","Rayon des bordures","Afficher tous","Appliquer","Veuillez remplir ce champ","Veuillez entrer une adresse web","Par défaut","Cercle","Point","Quadratique","Trouver","Précédent","Suivant","Le contenu que vous insérez provient d'un document Microsoft Word / Excel. Voulez-vous enregistrer le format ou l'effacer?","C'est peut-être un fragment de Word ou Excel","Nettoyer","Insérer un nom de classe","Appuyez sur Alt pour un redimensionnement personnalisé"]},53113(t){t.exports.default=["הקלד משהו...","About Jodit","Jodit Editor","Jodit User's Guide","contains detailed help for using.","For information about the license, please go to our website:","Buy full version","Copyright © XDSoft.net - Chupurnov Valeriy. All rights reserved.","מקום עיגון","פתח בכרטיסיה חדשה","פתח את העורך בחלון חדש","נקה עיצוב","שנה צבע טקסט או רקע","בצע שוב","בטל","מודגש","נטוי","הכנס רשימת תבליטים","הכנס רשימה ממוספרת","מרכז","ישר ","ישר לשמאל","ישר לימין","הכנס קו אופקי","הכנס תמונה","הכנס קובץ","הכנס סרטון וידאו מYouTube/Vimeo","הכנס קישור","גודל גופן","גופן","מעוצב מראש","רגיל","כותרת 1","כותרת 2","כותרת 3","כותרת 4","ציטוט","קוד","הכנס","הכנס טבלה","הקטן כניסה","הגדל כניסה","בחר תו מיוחד","הכנס תו מיוחד","העתק עיצוב","החלף מצב","ריווח","עליון","ימין","תחתון","שמאל","עיצוב CSS","מחלקת CSS","יישור","ימין","מרכז","שמאל","--לא נקבע--","מקור","כותרת","כיתוב חלופי","קישור","פתח בכרטיסיה חדשה","תמונה","קובץ","מתקדם","מאפייני תמונה","ביטול","אישור","סייר הקבצים","שגיאה בזמן טעינת רשימה","שגיאה בזמן טעינת תקיות","האם אתה בטוח?","הכנס שם תקיה","צור תקיה","סוג הקובץ","הסר תמונה","הסר קובץ","או לחץ","כיתוב חלופי","העלה","סייר","רקע","טקסט","עליון","מרכז","תחתון","הכנס עמודה לפני","הכנס עמודה אחרי","הכנס שורה מעל","הכנס שורה מתחת","מחק טבלה","מחק שורה","מחק עמודה","רוקן תא","תווים: %d","מילים: %d","קו חוצה","קו תחתון","superscript","subscript","גזור בחירה","בחר הכל","שבירת שורה","חפש","החלף ב","להחליף","הדבק","בחר תוכן להדבקה","HTML","מודגש","נטוי","מברשת","קישור","בטל","בצע שוב","טבלה","תמונה","מחק","פסקה","גודל גופן","וידאו","גופן","עלינו","הדפס","קו תחתון","קו חוצה","הגדל כניסה","הקטן כניסה","גודל מלא","כווץ","קו אופקי","רשימת תבליטים","רשימה ממוספרת","חתוך","בחר הכל","הוסף קוד","פתח קישור","ערוך קישור","ללא מעקב","בטל קישור","עדכן","כדי לערוך","הצג","כתובת","ערוך","יישור אופקי","סנן","מין לפי שינוי","מיין לפי שם","מיין לפי גודל","הוסף תקייה","אפס","שמור","שמור בשם...","שנה גודל","חתוך","רוחב","גובה","שמור יחס","כן","לא","הסר","בחר","נבחר: %s","יישור אנכי","פיצול","מזג","הוסף עמודה","הוסף שורה",null,"מחק","פיצול אנכי","פיצול אופקי","מסגרת","הקוד דומה לHTML, האם להשאיר כHTML","הדבק כHTML","השאר","הכנס כטקסט","הכנס טקסט בלבד","רק קבצים המשוייכים שלך ניתנים לעריכה. האם להוריד את הקובץ?","התמונה עלתה בהצלחה!","לוח","אין קבצים בספריה זו.","הונגרית","הזן שם חדש","תצוגה מקדימה","הורד","להדביק מהלוח","הדפדפן שלך לא תומך גישה ישירה ללוח.","העתק בחירה","העתק","רדיוס הגבול","הצג את כל","החל","נא למלא שדה זה","אנא הזן כתובת אינטרנט","ברירת המחדל","מעגל","נקודה","הריבוע הזה","למצוא","מצא את הקודם","חפש את הבא","התוכן המודבק מגיע ממסמך וורד/אקסל. האם ברצונך להשאיר את העיצוב או לנקותו",'זוהתה הדבקה מ"וורד"',"נקה","הכנס את שם הכיתה","לחץ על אלט לשינוי גודל מותאם אישית"]},81321(t){t.exports.default=["Írjon be valamit","Joditról","Jodit Editor","Jodit útmutató","további segítséget tartalmaz","További licence információkért látogassa meg a weboldalunkat:","Teljes verzió megvásárlása","Copyright © XDSoft.net - Chupurnov Valeriy. Minden jog fenntartva.","Horgony","Megnyitás új lapon","Megnyitás teljes méretben","Formázás törlése","Háttér/szöveg szín","Újra","Visszavon","Félkövér","Dőlt","Pontozott lista","Számozott lista","Középre zárt","Sorkizárt","Balra zárt","Jobbra zárt","Vízszintes vonal beszúrása","Kép beszúrás","Fájl beszúrás","Youtube videó beszúrása","Link beszúrás","Betűméret","Betűtípus","Formázott blokk beszúrása","Normál","Fejléc 1","Fejléc 2","Fejléc 3","Fejléc 4","Idézet","Kód","Beszúr","Táblázat beszúrása","Behúzás csökkentése","Behúzás növelése","Speciális karakter kiválasztása","Speciális karakter beszúrása","Kép formázása","Nézet váltása","Szegélyek","felső","jobb","alsó","bal","CSS stílusok","CSS osztályok","Igazítás","Jobbra","Középre","Balra","Nincs","Forrás","Cím","Helyettesítő szöveg","Link","Link megnyitása új lapon","Kép","Fájl","Haladó","Kép tulajdonságai","Mégsem","OK","Fájl tallózó","Hiba a lista betöltése közben","Hiba a mappák betöltése közben","Biztosan ezt szeretné?","Írjon be egy mappanevet","Mappa létrehozása","írjon be bevet","Húzza ide a képet","Húzza ide a fájlt","vagy kattintson","Helyettesítő szöveg","Feltölt","Tallóz","Háttér","Szöveg","Fent","Középen","Lent","Oszlop beszúrás elé","Oszlop beszúrás utána","Sor beszúrás fölé","Sor beszúrás alá","Táblázat törlése","Sor törlése","Oszlop törlése","Cella tartalmának törlése","Karakterek száma: %d","Szavak száma: %d","Áthúzott","Aláhúzott","Felső index","Alsó index","Kivágás","Összes kijelölése","Szünet","Keresés","Csere erre","Cserélje ki","Beillesztés","Válasszon tartalmat a beillesztéshez","HTML","Félkövér","Dőlt","Ecset","Link","Visszavon","Újra","Táblázat","Kép","Törlés","Paragráfus","Betűméret","Videó","Betű","Rólunk","Nyomtat","Aláhúzott","Áthúzott","Behúzás","Aussenseiter","Teljes méret","Összenyom","Egyenes vonal","Lista","Számozott lista","Kivág","Összes kijelölése","Beágyazott kód","Link megnyitása","Link szerkesztése","Nincs követés","Link leválasztása","Frissít","Szerkesztés","felülvizsgálat","URL","Szerkeszt","Vízszintes igazítás","Szűrő","Rendezés módosítás szerint","Rendezés név szerint","Rendezés méret szerint","Mappa hozzáadás","Visszaállít","Mentés","Mentés másként...","Átméretezés","Kivág","Szélesség","Magasság","Képarány megtartása","Igen","Nem","Eltávolít","Kijelöl","Kijelöl: %s","Függőleges igazítás","Felosztás","Összevonás","Oszlop hozzáadás","Sor hozzáadás",null,"Törlés","Függőleges felosztás","Vízszintes felosztás","Szegély","A beillesztett szöveg HTML-nek tűnik. Megtartsuk HTML-ként?","Beszúrás HTML-ként","Megtartás","Beszúrás szövegként","Csak szöveg beillesztése","Csak a saját képeit tudja szerkeszteni. Letölti ezt a képet?","Kép sikeresen feltöltve!","Palette","Er zijn geen bestanden in deze map.","átnevezés","Adja meg az új nevet","előnézet","Letöltés","Illessze be a vágólap","A böngésző nem támogatja a közvetlen hozzáférést biztosít a vágólapra.","Másolás kiválasztása","másolás","Határ sugár","Összes","Alkalmazni","Kérjük, töltse ki ezt a mezőt,","Kérjük, írja be a webcímet","Alapértelmezett","Kör","Pont","Quadrate","Találni","Megtalálja Előző","Következő Keresése","A beillesztett tartalom Microsoft Word/Excel dokumentumból származik. Meg szeretné tartani a formátumát?","Word-ből másolt szöveg","Elvetés","Helyezze be az osztály nevét","Nyomja meg az Alt egyéni átméretezés"]},4679(t){t.exports.default=["Ketik sesuatu","Tentang Jodit","Editor Jodit","Panduan Pengguna Jodit","mencakup detail bantuan penggunaan","Untuk informasi tentang lisensi, silakan kunjungi website:","Beli versi lengkap","Hak Cipta © XDSoft.net - Chupurnov Valeriy. Hak cipta dilindungi undang-undang.","Tautan","Buka di tab baru","Buka editor dalam ukuran penuh","Hapus Pemformatan","Isi warna atau atur warna teks","Ulangi","Batalkan","Tebal","Miring","Sisipkan Daftar Tidak Berurut","Sisipkan Daftar Berurut","Tengah","Penuh","Kiri","Kanan","Sisipkan Garis Horizontal","Sisipkan Gambar","Sisipkan Berkas","Sisipkan video youtube/vimeo","Sisipkan tautan","Ukuran font","Keluarga font","Sisipkan blok format","Normal","Heading 1","Heading 2","Heading 3","Heading 4","Kutip","Kode","Sisipkan","Sisipkan tabel","Kurangi Indentasi","Tambah Indentasi","Pilih Karakter Spesial","Sisipkan Karakter Spesial","Formar warna","Ubah mode","Batas","atas","kanan","bawah","kiri","Gaya","Class","Rata","Kanan","Tengah","Kiri","--Tidak diset--","Src","Judul","Teks alternatif","Tautan","Buka tautan di tab baru","Gambar","berkas","Lanjutan","Properti gambar","Batal","Ya","Penjelajah Berkas","Error ketika memuat list","Error ketika memuat folder","Apakah Anda yakin?","Masukkan nama Direktori","Buat direktori","ketik nama","Letakkan gambar","Letakkan berkas","atau klik","Teks alternatif","Unggah","Jelajahi","Latar Belakang","Teks","Atas","Tengah","Bawah","Sisipkan kolom sebelumnya","Sisipkan kolom setelahnya","Sisipkan baris di atasnya","Sisipkan baris di bawahnya","Hapus tabel","Hapus baris","Hapus kolom","Kosongkan cell","Karakter: %d","Kata: %d","Coret","Garis Bawah","Superskrip","Subskrip","Potong pilihan","Pilih semua","Berhenti","Mencari","Ganti dengan","Mengganti","Paste","Pilih konten untuk dipaste","sumber","tebal","miring","sikat","tautan","batalkan","ulangi","tabel","gambar","penghapus","paragraf","ukuran font","video","font","tentang","cetak","garis bawah","coret","menjorok ke dalam","menjorok ke luar","ukuran penuh","menyusut","hr","ul","ol","potong","Pilih semua","Kode embed","Buka tautan","Edit tautan","No follow","Hapus tautan","Perbarui","pensil","Mata","URL","Edit","Perataan horizontal","Filter","Urutkan berdasarkan perubahan","Urutkan berdasarkan nama","Urutkan berdasarkan ukuran","Tambah folder","Reset","Simpan","Simpan sebagai...","Ubah ukuran","Crop","Lebar","Tinggi","Jaga aspek rasio","Ya","Tidak","Copot","Pilih","Pilih %s","Rata vertikal","Bagi","Gabungkan","Tambah kolom","tambah baris","Lisensi: %s","Hapus","Bagi secara vertikal","Bagi secara horizontal","Bingkai","Kode Anda cenderung ke HTML. Biarkan sebagai HTML?","Paste sebagai HTML","Jaga","Sisipkan sebagai teks","Sisipkan hanya teks","Anda hanya dapat mengedit gambar Anda sendiri. Unduh gambar ini di host?","Gambar telah sukses diunggah ke host!","palet","Tidak ada berkas","ganti nama","Masukkan nama baru","pratinjau","Unduh","Paste dari clipboard","Browser anda tidak mendukung akses langsung ke clipboard.","Copy seleksi","copy","Border radius","Tampilkan semua","Menerapkan","Silahkan mengisi kolom ini","Silahkan masukkan alamat web","Default","Lingkaran","Dot","Kuadrat","Menemukan","Menemukan Sebelumnya","Menemukan Berikutnya","Konten dipaste dari dokumen Microsoft Word/Excel. Apakah Anda ingin tetap menjaga format atau membersihkannya?","Terdeteksi paste dari Word","Bersih","Masukkan nama kelas","Tekan Alt untuk mengubah ukuran kustom"]},31927(t){t.exports.default=["Scrivi qualcosa...","A proposito di Jodit","Jodit Editor","Guida utente di Jodit","contiene una guida dettagliata per l'uso.","Per informazioni sulla licenza, si prega di visitare il nostro sito web:","Acquista la versione completa","Copyright © XDSoft.net - Chupurnov Valeriy. Tutti i diritti riservati.","Link","Apri in una nuova scheda","Apri l'editor a schermo intero","Pulisci Formattazione","Colore di sfondo o del testo","Ripristina","Annulla","Grassetto","Corsivo","Inserisci lista non ordinata","Inserisci lista ordinata","Allinea al centro","Allineamento Giustificato","Allinea a Sinistra","Allinea a Destra","Inserisci una linea orizzontale","Inserisci immagine","Inserisci un file","Inserisci video Youtube/Vimeo","Inserisci link","Dimensione carattere","Tipo di font","Inserisci blocco","Normale","Intestazione 1","Intestazione 2","Intestazione 3","Intestazione 4","Citazione","Codice","Inserisci","Inserisci tabella","Riduci il rientro","Aumenta il rientro","Seleziona un carattere speciale","Inserisci un carattere speciale","Copia formato","Cambia modalita'","Margini","su","destra","giù","sinistra","Stili CSS","Classi CSS","Allinea","Destra","Centro","Sinistra","--Non Impostato--","Fonte","Titolo","Testo Alternativo","Link","Apri il link in una nuova scheda","Immagine","Archivio","Avanzato","Proprietà dell'immagine","Annulla","Accetta","Cerca file","Errore durante il caricamento dell'elenco","Errore durante il caricamento delle cartelle","Sei sicuro?","Inserisci il nome della cartella","Crea cartella","Digita il nome","Cancella immagine","Cancella file","o clicca","Testo alternativo","Carica","Sfoglia","Sfondo","Testo","Su","Centro","Sotto","Inserisci la colonna prima","Inserisci la colonna dopo","Inserisci la riga sopra","Inserisci la riga sotto","Elimina tabella","Elimina riga","Elimina colonna","Cella vuota","Caratteri: %d","Parole: %d","Barrato","Sottolineato","indice","pedice","Taglia selezione","Seleziona tutto","Pausa","Cerca per","Sostituisci con","Sostituisci","Incolla","Seleziona il contenuto da incollare","risorsa","Grassetto","Corsivo","Pennello","Link","Annulla","Ripristina","Tabella","Immagine","Gomma","Paragrafo","Dimensione del carattere","Video","Font","Approposito di","Stampa","Sottolineato","Barrato","aumenta rientro","riduci rientro","espandi","comprimi","linea orizzontale","lista non ordinata","lista ordinata","Taglia","Seleziona tutto","Includi codice","Apri link","Modifica link","Non seguire","Rimuovi link","Aggiorna","Per modificare","Recensione"," URL","Modifica","Allineamento orizzontale","Filtro","Ordina per data di modifica","Ordina per nome","Ordina per dimensione","Aggiungi cartella","Reset","Salva","Salva con nome...","Ridimensiona","Ritaglia","Larghezza","Altezza","Mantieni le proporzioni","Si","No","Rimuovi","Seleziona","Seleziona: %s","Allineamento verticala","Dividi","Fondi","Aggiungi colonna","Aggiungi riga",null,"Cancella","Dividi verticalmente","Dividi orizzontale","Bordo","Il codice è simile all'HTML. Mantieni come HTML?","Incolla come HTML","Mantieni","Inserisci come testo","Inserisci solo il testo","Puoi modificare solo le tue immagini. Vuoi scaricare questa immagine dal server?","L'immagine è stata caricata correttamente sul server!","tavolozza","Non ci sono file in questa directory.","Rinomina","Inserisci un nuovo nome","anteprima","Scarica","Incolla dagli appunti","Il tuo browser non supporta l'accesso diretto agli appunti.","Copia selezione","copia","Border radius","Mostra tutti","Applica","Si prega di compilare questo campo","Si prega di inserire un indirizzo web","Default","Cerchio","Punto","Quadrato","Trova","Trova Precedente","Trova Successivo","Il contenuto incollato proviene da un documento Microsoft Word / Excel. Vuoi mantenere il formato o pulirlo?","Incolla testo da Word rilevato","Pulisci","Inserisci il nome della classe","Premere Alt per il ridimensionamento personalizzato"]},21195(t){t.exports.default=["なにかタイプしてください","Joditについて","Jodit Editor","Jodit ユーザーズ・ガイド","詳しい使い方","ライセンス詳細についてはJodit Webサイトを確認ください:","フルバージョンを購入","Copyright © XDSoft.net - Chupurnov Valeriy. All rights reserved.","Anchor","新しいタブで開く","エディターのサイズ(フル/ノーマル)","書式をクリア","テキストの色","やり直し","元に戻す","太字","斜体","箇条書き","番号付きリスト","中央揃え","両端揃え","左揃え","右揃え","区切り線を挿入","画像を挿入","ファイルを挿入","Youtube/Vimeo 動画","リンクを挿入","フォントサイズ","フォント","テキストのスタイル","指定なし","タイトル1","タイトル2","タイトル3","タイトル4","引用","コード","挿入","表を挿入","インデント減","インデント増","特殊文字を選択","特殊文字を挿入","書式を貼付け","編集モード切替え","マージン","上","右","下","左","スタイル","クラス","配置","右寄せ","中央寄せ","左寄せ","指定なし","ソース","タイトル","代替テキスト","リンク","新しいタブで開く","画像","ファイル","高度な設定","画像のプロパティー","キャンセル","確定","File Browser","Error on load list","Error on load folders","Are you sure?","Enter Directory name","Create directory","type name","ここに画像をドロップ","ここにファイルをドロップ","or クリック","代替テキスト","アップロード","ブラウズ","背景","文字","上","中央","下","左に列を挿入","右に列を挿入","上に行を挿入","下に行を挿入","表を削除","行を削除","列を削除","セルを空にする","文字数: %d","単語数: %d","取り消し線","下線","上付き文字","下付き文字","切り取り","すべて選択","Pause","検索","置換","交換","貼付け","選択した内容を貼付け","source","bold","italic","brush","link","undo","redo","table","image","eraser","paragraph","fontsize","video","font","about","print","underline","strikethrough","indent","outdent","fullsize","shrink","分割線","箇条書き","番号付きリスト","切り取り","すべて選択","埋め込みコード","リンクを開く","リンクを編集","No follow","リンク解除","更新","鉛筆","サイトを確認","URL","編集","水平方向の配置","Filter","Sort by changed","Sort by name","Sort by size","Add folder","リセット","保存","Save as ...","リサイズ","Crop","幅","高さ","縦横比を保持","はい","いいえ","移除","選択","選択: %s","垂直方向の配置","分割","セルの結合","列を追加","行を追加",null,"削除","セルの分割(垂直方向)","セルの分割(水平方向)","境界線","HTMLコードを保持しますか?","HTMLで貼付け","HTMLを保持","HTMLをテキストにする","テキストだけ","You can only edit your own images. Download this image on the host?","The image has been successfully uploaded to the host!","パレット","There are no files","Rename","Enter new name","プレビュー","ダウンロード","貼り付け","お使いのブラウザはクリップボードを使用できません","コピー","copy","角の丸み","全て表示","適用","まだこの分野","を入力してくださいウェブアドレス","デフォルト","白丸","黒丸","四角","見","探前","由来","The pasted content is coming from a Microsoft Word/Excel document. Do you want to keep the format or clean it up?","Word Paste Detected","Clean","クラス名を挿入","カスタムサイズ変更のためのAltキーを押します"]},53414(t){t.exports.default=["Type something","About Jodit","Jodit Editor","Jodit User's Guide","contains detailed help for using","For information about the license, please go to our website:","Buy full version","Copyright © XDSoft.net - Chupurnov Valeriy. All rights reserved.","Anchor","Open in new tab","Open in fullsize","Clear Formatting","Fill color or set the text color","Redo","Undo","Bold","Italic","Insert Unordered List","Insert Ordered List","Align Center","Align Justify","Align Left","Align Right","Insert Horizontal Line","Insert Image","Insert file","Insert youtube/vimeo video","Insert link","Font size","Font family","Insert format block","Normal","Heading 1","Heading 2","Heading 3","Heading 4","Quote","Code","Insert","Insert table","Decrease Indent","Increase Indent","Select Special Character","Insert Special Character","Paint format","Change mode","Margins","top","right","bottom","left","Styles","Classes","Align","Right","Center","Left","--Not Set--","Src","Title","Alternative","Link","Open link in new tab","Image","file","Advanced","Image properties","Cancel","Ok","File Browser","Error on load list","Error on load folders","Are you sure?","Enter Directory name","Create directory","type name","Drop image","Drop file","or click","Alternative text","Upload","Browse","Background","Text","Top","Middle","Bottom","Insert column before","Insert column after","Insert row above","Insert row below","Delete table","Delete row","Delete column","Empty cell","Chars: %d","Words: %d","Strike through","Underline","superscript","subscript","Cut selection","Select all","Break","Search for","Replace with","Replace","Paste","Choose Content to Paste","source","bold","italic","brush","link","undo","redo","table","image","eraser","paragraph","fontsize","video","font","about","print","underline","strikethrough","indent","outdent","fullsize","shrink","hr","ul","ol","cut","selectall","Embed code","Open link","Edit link","No follow","Unlink","Update","pencil","Eye"," URL","Edit","Horizontal align","Filter","Sort by changed","Sort by name","Sort by size","Add folder","Reset","Save","Save as ...","Resize","Crop","Width","Height","Keep Aspect Ratio","Yes","No","Remove","Select","Select %s","Vertical align","Split","Merge","Add column","Add row","License: %s","Delete","Split vertical","Split horizontal","Border","Your code is similar to HTML. Keep as HTML?","Paste as HTML","Keep","Insert as Text","Insert only Text","You can only edit your own images. Download this image on the host?","The image has been successfully uploaded to the host!","palette","There are no files","Rename","Enter new name","preview","download","Paste from clipboard","Your browser doesn't support direct access to the clipboard.","Copy selection","copy","Border radius","Show all","Apply","Please fill out this field","Please enter a web address","Default","Circle","Dot","Quadrate","Find","Find Previous","Find Next","The pasted content is coming from a Microsoft Word/Excel document. Do you want to keep the format or clean it up?","Word Paste Detected","Clean","Insert className","Press Alt for custom resizing"]},11012(t){t.exports.default=["무엇이든 입력하세요","Jodit에 대하여","Jodit Editor","Jodit 사용자 안내서","자세한 도움말이 들어있어요","라이센스에 관해서는 Jodit 웹 사이트를 방문해주세요:","풀 버전 구입하기","© XDSoft.net - Chupurnov Valeriy. 에게 저작권과 모든 권리가 있습니다.","Anchor","새 탭에서 열기","전체 크기로 보기","서식 지우기","글씨 색상","재실행","실행 취소","굵게","기울임","글머리 목록","번호 목록","가운데 정렬","양쪽 정렬","왼쪽 정렬","오른쪽 정렬","수평 구분선 넣기","이미지 넣기","파일 넣기","Youtube/Vimeo 동영상","링크 넣기","글꼴 크기","글꼴","블록 요소 넣기","일반 텍스트","제목 1","제목 2","제목 3","제목 4","인용","코드","붙여 넣기","테이블","들여쓰기 감소","들여쓰기 증가","특수문자 선택","특수문자 입력","페인트 형식","편집모드 변경","마진","위","오른쪽","아래","왼쪽","스타일","클래스","정렬","오른쪽으로","가운데로","왼쪽으로","--지정 안 함--","경로(src)","제목","대체 텍스트(alt)","링크","새 탭에서 열기",null,"파일","고급","이미지 속성","취소","확인","파일 탐색기","목록 불러오기 에러","폴더 불러오기","정말 진행할까요?","디렉토리 이름 입력","디렉토리 생성","이름 입력","이미지 드래그","파일 드래그","혹은 클릭","대체 텍스트","업로드","탐색","배경","텍스트","위","중앙","아래","이전 열에 삽입","다음 열에 삽입","위 행에 삽입","아래 행에 삽입","테이블 삭제","행 삭제","열 삭제","빈 셀","문자수: %d","단어수: %d","취소선","밑줄","윗첨자","아래첨자","선택 잘라내기","모두 선택","구분자","검색","대체하기","대체","붙여넣기","붙여넣을 내용 선택","HTML 소스","볼드","이탤릭","브러시","링크","실행 취소","재실행","테이블","이미지","지우개","문단","글꼴 크기","비디오","글꼴","편집기 정보","프린트","밑줄","취소선","들여쓰기","내어쓰기","전체 화면","일반 화면","구분선","글머리 목록","번호 목록","잘라내기","모두 선택","Embed 코드","링크 열기","링크 편집","No follow","링크 제거","갱신","연필","사이트 확인","URL","편집","수평 정렬","필터","변경일 정렬","이름 정렬","크기 정렬","새 폴더","초기화","저장","새로 저장하기 ...","리사이즈","크롭","가로 길이","세로 높이","비율 유지하기","네","아니오","제거","선택","선택: %s","수직 정렬","분할","셀 병합","열 추가","행 추가","라이센스: %s","삭제","세로 셀 분할","가로 셀 분할","외곽선","HTML 코드로 감지했어요. 코드인채로 붙여넣을까요?","HTML로 붙여넣기","원본 유지","텍스트로 넣기","텍스트만 넣기","외부 이미지는 편집할 수 없어요. 외부 이미지를 다운로드 할까요?","이미지를 무사히 업로드 했어요!","팔레트","파일이 없어요","이름 변경","새 이름 입력","미리보기","다운로드","클립보드 붙여넣기","사용중인 브라우저가 클립보드 접근을 지원하지 않아요.","선택 복사","복사","둥근 테두리","모두 보기","적용","이 항목을 입력해주세요!","웹 URL을 입력해주세요.","기본","원","점","정사각형","찾기","이전 찾기","다음 찾기","Microsoft Word/Excel 문서로 감지했어요. 서식을 유지한채로 붙여넣을까요?","Word 붙여넣기 감지","지우기","className 입력","사용자 지정 크기 조정에 대 한 고도 누르십시오"]},87061(t){t.exports.default=["Бичээд үзээрэй","Jodit-ын талаар ","Jodit програм","Jodit гарын авлага","хэрэглээний талаар дэлгэрэнгүй мэдээллийг агуулна","Лицензийн мэдээллийг манай вэб хуудаснаас авна уу:","Бүрэн хувилбар худалдан авах","Зохиогчийн эрх хамгаалагдсан © XDSoft.net - Chupurnov Valeriy. Бүх эрхийг эзэмшинэ.","Холбоо барих","Шинэ табаар нээх","Бүтэн дэлгэцээр нээх","Форматыг арилгах","Өнгөөр будах эсвэл текстийн өнгө сонгох","Дахих","Буцаах","Тод","Налуу","Тэмдэгт жагсаалт нэмэх","Дугаарт жагсаалт нэмэх","Голлож байрлуулах","Тэгшитгэн байрлуулах","Зүүнд байрлуулах","Баруунд байрлуулах","Хэвтээ зураас нэмэх","Зураг нэмэх","Файл нэмэх","Youtube/Vimeo видео нэмэх","Холбоос нэмэх","Фонтын хэмжээ","Фонтын бүл","Блок нэмэх","Хэвийн","Гарчиг 1","Гарчиг 2","Гарчиг 3","Гарчиг 4","Ишлэл","Код","Оруулах","Хүснэгт оруулах","Доголын зай хасах","Доголын зай нэмэх","Тусгай тэмдэгт сонгох","Тусгай тэмдэгт нэмэх","Зургийн формат","Горим өөрчлөх","Цаасны зай","Дээрээс","Баруунаас","Доороос","Зүүнээс","CSS стиль","CSS анги","Байрлуулах","Баруун","Төв","Зүүн","--Тодорхойгүй--","Эх үүсвэр","Гарчиг","Алтернатив текст","Холбоос","Холбоосыг шинэ хавтсанд нээх","Зураг","Файл","Дэвшилтэт","Зургийн үзүүлэлт","Цуцлах","Ok","Файлын цонх","Жагсаалт татах үед алдаа гарлаа","Хавтас татах үед алдаа гарлаа","Итгэлтэй байна уу?","Хавтсын нэр оруулах","Хавтас үүсгэх","Нэр бичих","Зураг буулгах","Файл буулгах","эсвэл товш","Алтернатив текст","Байршуулах","Үзэх","Арын зураг","Текст","Дээр","Дунд","Доор","Урд нь багана нэмэх","Ард нь багана нэмэх","Дээр нь мөр нэмэх","Доор нь мөр нэмэх","Хүснэгт устгах","Мөр устгах","Багана устгах","Нүд цэвэрлэх","Тэмдэгт: %d","Үг: %d","Дээгүүр зураас","Доогуур зураас","Дээд индекс","Доод индекс","Сонголтыг таслах","Бүгдийг сонго","Мөрийг таслах","Хайх","Үүгээр солих","Солих","Буулгах","Буулгах агуулгаа сонгоно уу","Эх үүсвэр","Тод","Налуу","Будах","Холбоос","Буцаах","Дахих","Хүснэгт","Зураг","Баллуур","Параграф","Фонтын хэмжээ","Видео","Фонт","Тухай","Хэвлэх","Доогуур зураас","Дээгүүр зураас","Догол нэмэх","Догол багасгах","Бүтэн дэлгэц","Багасга","Хаалт","Тэмдэгт жагсаалт","Дугаарласан жагсаалт","Таслах","Бүгдийг сонго","Код оруулах","Холбоос нээх","Холбоос засах","Nofollow özelliği","Холбоос салгах","Шинэчлэх","Засах","Нүд","URL","Засах","Хэвтээ эгнүүлэх","Шүүх","Сүүлд өөрчлөгдсөнөөр жагсаах","Нэрээр жагсаах","Хэмжээгээр жагсаах","Хавтас нэмэх","Буцаах","Хадгалах","Өөрөөр хадгалах","Хэмжээг өөрчил","Тайрах","Өргөн","Өндөр","Харьцааг хадгал","Тийм","Үгүй","Арилга","Сонго","Сонго: %s","Босоо эгнүүлэх","Задлах","Нэгтгэх","Багана нэмэх","Мөр нэмэх",null,"Устгах","Баганаар задлах","Мөрөөр задлах","Хүрээ","Таны код HTML кодтой адил байна. HTML форматаар үргэлжлүүлэх үү?","HTML байдлаар буулгах","Хадгалах","Текст байдлаар нэмэх","Зөвхөн текст оруулах","Та зөвхөн өөрийн зургуудаа янзлах боломжтой. Энэ зургийг өөр лүүгээ татмаар байна уу?","Зургийг хост руу амжилттай хадгалсан","Палет","Энд ямар нэг файл алга","Шинээр нэрлэх","Шинэ нэр оруулна уу","Урьдчилан харах","Татах","Самбараас хуулах ","Энэ вэб хөтчөөс самбарт хандах эрх алга.","Сонголтыг хуул","Хуулах","Хүрээний радиус","Бүгдийг харуулах","Хэрэгжүүл","Энэ талбарыг бөглөнө үү","Вэб хаягаа оруулна уу","Үндсэн","Дугуй","Цэг","Дөрвөлжин","Хайх","Өмнөхийг ол","Дараагийнхийг ол","Буулгасан агуулга Microsoft Word/Excel форматтай байна. Энэ форматыг хэвээр хадгалах уу эсвэл арилгах уу?","Word байдлаар буулгасан байна","Цэвэрлэх","Бүлгийн нэрээ оруулна уу","Хэмжээсийг шинээр өөчрлөхийн тулд Alt товчин дээр дарна уу"]},3268(t){t.exports.default=["Begin met typen..","Over Jodit","Jodit Editor","Jodit gebruikershandleiding","bevat gedetailleerde informatie voor gebruik.","Voor informatie over de licentie, ga naar onze website:","Volledige versie kopen","Copyright © XDSoft.net - Chupurnov Valeriy. Alle rechten voorbehouden.","Anker","Open in nieuwe tab","Editor in volledig scherm openen","Opmaak verwijderen","Vulkleur of tekstkleur aanpassen","Opnieuw","Ongedaan maken","Vet","Cursief","Geordende list invoegen","Ongeordende lijst invoegen","Centreren","Uitlijnen op volledige breedte","Links uitlijnen","Rechts uitlijnen","Horizontale lijn invoegen","Afbeelding invoegen","Bestand invoegen","Youtube/Vimeo video invoegen","Link toevoegen","Tekstgrootte","Lettertype","Format blok invoegen","Normaal","Koptekst 1","Koptekst 2","Koptekst 3","Koptekst 4","Citaat","Code","Invoegen","Tabel invoegen","Inspringing verkleinen","Inspringing vergroten","Symbool selecteren","Symbool invoegen","Opmaak kopieren","Modus veranderen","Marges","Boven","Rechts","Onder","Links","CSS styles","CSS classes","Uitlijning","Rechts","Gecentreerd","Links","--Leeg--","Src","Titel","Alternatieve tekst","Link","Link in nieuwe tab openen","Afbeelding","Bestand","Geavanceerd","Afbeeldingseigenschappen","Annuleren","OK","Bestandsbrowser","Fout bij het laden van de lijst","Fout bij het laden van de mappenlijst","Weet je het zeker?","Geef de map een naam","Map aanmaken","Type naam","Sleep hier een afbeelding naartoe","Sleep hier een bestand naartoe","of klik","Alternatieve tekst","Uploaden","Bladeren","Achtergrond","Tekst","Boven","Midden","Onder","Kolom invoegen (voor)","Kolom invoegen (na)","Rij invoegen (boven)","Rij invoegen (onder)","Tabel verwijderen","Rij verwijderen","Kolom verwijderen","Cel leegmaken","Tekens: %d","Woorden: %d","Doorstrepen","Onderstrepen","Superscript","Subscript","Selectie knippen","Selecteer alles","Enter","Zoek naar","Vervangen door","Vervangen","Plakken","Kies content om te plakken","Broncode","vet","cursief","kwast","link","ongedaan maken","opnieuw","tabel","afbeelding","gum","paragraaf","lettergrootte","video","lettertype","over","afdrukken","onderstreept","doorgestreept","inspringen","minder inspringen","volledige grootte","kleiner maken","horizontale lijn","lijst","genummerde lijst","knip","alles selecteren","Embed code","Link openen","Link aanpassen","Niet volgen","link verwijderen","Updaten","Om te bewerken","Recensie"," URL","Bewerken","Horizontaal uitlijnen","Filteren","Sorteren op wijzigingsdatum","Sorteren op naam","Sorteren op grootte","Map toevoegen","Herstellen","Opslaan","Opslaan als ...","Grootte aanpassen","Bijknippen","Breedte","Hoogte","Verhouding behouden","Ja","Nee","Verwijderen","Selecteren","Selecteer: %s","Verticaal uitlijnen","Splitsen","Samenvoegen","Kolom toevoegen","Rij toevoegen",null,"Verwijderen","Verticaal splitsen","Horizontaal splitsen","Rand","Deze code lijkt op HTML. Als HTML behouden?","Invoegen als HTML","Origineel behouden","Als tekst invoegen","Als onopgemaakte tekst invoegen","Je kunt alleen je eigen afbeeldingen aanpassen. Deze afbeelding downloaden?","De afbeelding is succesvol geüploadet!","Palette","Er zijn geen bestanden in deze map.","Hernoemen","Voer een nieuwe naam in","Voorvertoning","Download","Plakken van klembord","Uw browser ondersteunt geen directe toegang tot het klembord.","Selectie kopiëren","kopiëren","Border radius","Toon alle","Toepassen","Vul dit veld in","Voer een webadres in","Standaard","Cirkel","Punt","Kwadraat","Zoeken","Vorige Zoeken","Volgende Zoeken","De geplakte tekst is afkomstig van een Microsoft Word/Excel document. Wil je de opmaak behouden of opschonen?","Word-tekst gedetecteerd","Opschonen","Voeg de klassenaam in","Druk op Alt voor aangepaste grootte"]},97834(t){t.exports.default=["Napisz coś","O Jodit","Edytor Jodit","Instrukcja Jodit","zawiera szczegółowe informacje dotyczące użytkowania.","Odwiedź naszą stronę, aby uzyskać więcej informacji na temat licencji:","Zakup pełnej wersji","Copyright © XDSoft.net - Chupurnov Valeriy. Wszystkie prawa zastrzeżone.","Kotwica","Otwórz w nowej zakładce","Otwórz edytor w pełnym rozmiarze","Wyczyść formatowanie","Kolor wypełnienia lub ustaw kolor tekstu","Ponów","Cofnij","Pogrubienie","Kursywa","Wstaw listę wypunktowaną","Wstaw listę numeryczną","Wyśrodkuj","Wyjustuj","Wyrównaj do lewej","Wyrównaj do prawej","Wstaw linię poziomą","Wstaw grafikę","Wstaw plik","Wstaw film Youtube/vimeo","Wstaw link","Rozmiar tekstu","Krój czcionki","Wstaw formatowanie","Normalne","Nagłówek 1","Nagłówek 2","Nagłówek 3","Nagłówek 4","Cytat","Kod","Wstaw","Wstaw tabelę","Zmniejsz wcięcie","Zwiększ wcięcie","Wybierz znak specjalny","Wstaw znak specjalny","Malarz formatów","Zmień tryb","Marginesy","Górny","Prawy","Dolny","Levy","Style CSS","Klasy CSS","Wyrównanie","Prawa","środek","Lewa","brak","Źródło","Tytuł","Tekst alternatywny","Link","Otwórz w nowej zakładce","Grafika","Plik","Zaawansowane","Właściwości grafiki","Anuluj","OK","Przeglądarka plików","Błąd ładowania listy plików","Błąd ładowania folderów","Czy jesteś pewien?","Wprowadź nazwę folderu","Utwórz folder","wprowadź nazwę","Upuść plik graficzny","Upuść plik","lub kliknij tu","Tekst alternatywny","Wczytaj","Przeglądaj","Tło","Treść","Góra","Środek","Dół","Wstaw kolumnę przed","Wstaw kolumnę po","Wstaw wiersz przed","Wstaw wiersz po","Usuń tabelę","Usuń wiersz","Usuń kolumnę","Wyczyść komórkę","Znaki: %d","Słowa: %d","Przekreślenie","Podkreślenie","indeks górny","index dolny","Wytnij zaznaczenie","Wybierz wszystko","Przerwa","Szukaj","Zamień na","Wymienić","Wklej","Wybierz zawartość do wklejenia","HTML","pogrubienie","kursywa","pędzel","link","cofnij","ponów","tabela","grafika","wyczyść","akapit","rozmiar czcionki","wideo","czcionka","O programie","drukuj","podkreślenie","przekreślenie","wcięcie","wycięcie","pełen rozmiar","przytnij","linia pozioma","lista","lista numerowana","wytnij","zaznacz wszystko","Wstaw kod","otwórz link","edytuj link","Atrybut no-follow","Usuń link","Aktualizuj","edytuj","szukaj","URL","Edytuj","Wyrównywanie w poziomie","Filtruj","Sortuj wg zmiany","Sortuj wg nazwy","Sortuj wg rozmiaru","Dodaj folder","wyczyść","zapisz","zapisz jako","Zmień rozmiar","Przytnij","Szerokość","Wysokość","Zachowaj proporcje","Tak","Nie","Usuń","Wybierz","Wybierz: %s","Wyrównywanie w pionie","Podziel","Scal","Dodaj kolumnę","Dodaj wiersz",null,"Usuń","Podziel w pionie","Podziel w poziomie","Obramowanie","Twój kod wygląda jak HTML. Zachować HTML?","Wkleić jako HTML?","Oryginalny tekst","Wstaw jako tekst","Wstaw tylko treść","Możesz edytować tylko swoje grafiki. Czy chcesz pobrać tą grafikę?","Grafika została pomyślnienie dodana na serwer","Paleta","Brak plików.","zmień nazwę","Wprowadź nową nazwę","podgląd","pobierz","Wklej ze schowka","Twoja przeglądarka nie obsługuje schowka","Kopiuj zaznaczenie","kopiuj","Zaokrąglenie krawędzi","Pokaż wszystkie","Zastosuj","Proszę wypełnić to pole","Proszę, wpisz adres sieci web","Domyślnie","Koło","Punkt","Kwadrat","Znaleźć","Znaleźć Poprzednie","Znajdź Dalej","Wklejany tekst pochodzi z dokumentu Microsoft Word/Excel. Chcesz zachować ten format czy wyczyścić go? ","Wykryto tekst w formacie Word","Wyczyść","Wstaw nazwę zajęć","Naciśnij Alt, aby zmienić rozmiar"]},86433(t){t.exports.default=["Escreva algo...","Sobre o Jodit","Editor Jodit","Guia de usuário Jodit","contém ajuda detalhada para o uso.","Para informação sobre a licença, por favor visite nosso site:","Compre a versão completa","Copyright © XDSoft.net - Chupurnov Valeriy. Todos os direitos reservados.","Link","Abrir em nova aba","Abrir editor em tela cheia","Limpar formatação","Cor de preenchimento ou cor do texto","Refazer","Desfazer","Negrito","Itálico","Inserir lista não ordenada","Inserir lista ordenada","Centralizar","Justificar","Alinhar à Esquerda","Alinhar à Direita","Inserir linha horizontal","Inserir imagem","Inserir arquivo","Inserir vídeo do Youtube/vimeo","Inserir link","Tamanho da letra","Fonte","Inserir bloco","Normal","Cabeçalho 1","Cabeçalho 2","Cabeçalho 3","Cabeçalho 4","Citação","Código","Inserir","Inserir tabela","Diminuir recuo","Aumentar recuo","Selecionar caractere especial","Inserir caractere especial","Copiar formato","Mudar modo","Margens","cima","direta","baixo","esquerda","Estilos CSS","Classes CSS","Alinhamento","Direita","Centro","Esquerda","--Não Estabelecido--","Fonte","Título","Texto Alternativo","Link","Abrir link em nova aba","Imagem","Arquivo","Avançado","Propriedades da imagem","Cancelar","Ok","Procurar arquivo","Erro ao carregar a lista","Erro ao carregar as pastas","Você tem certeza?","Escreva o nome da pasta","Criar pasta","Escreva seu nome","Soltar imagem","Soltar arquivo","ou clique","Texto alternativo","Upload","Explorar","Fundo","Texto","Cima","Meio","Baixo","Inserir coluna antes","Inserir coluna depois","Inserir linha acima","Inserir linha abaixo","Excluir tabela","Excluir linha","Excluir coluna","Limpar célula","Caracteres: %d","Palavras: %d","Tachado","Sublinhar","sobrescrito","subscrito","Cortar seleção","Selecionar tudo","Pausa","Procurar por","Substituir com","Substituir","Colar","Escolher conteúdo para colar","HTML","negrito","itálico","pincel","link","desfazer","refazer","tabela","imagem","apagar","parágrafo","tamanho da letra","vídeo","fonte","Sobre de","Imprimir","sublinhar","tachado","recuar","diminuir recuo","Tamanho completo","diminuir","linha horizontal","lista não ordenada","lista ordenada","Cortar","Selecionar tudo","Incluir código","Abrir link","Editar link","Não siga","Remover link","Atualizar","Editar","Visualizar","URL","Editar","Alinhamento horizontal","filtrar","Ordenar por modificação","Ordenar por nome","Ordenar por tamanho","Adicionar pasta","Resetar","Salvar","Salvar como...","Redimensionar","Recortar","Largura","Altura","Manter a proporção","Sim","Não","Remover","Selecionar","Selecionar: %s","Alinhamento vertical","Dividir","Mesclar","Adicionar coluna","Adicionar linha",null,"Excluir","Dividir vertical","Dividir horizontal","Borda","Seu código é similar ao HTML. Manter como HTML?","Colar como HTML?","Manter","Inserir como Texto","Inserir somente o Texto","Você só pode editar suas próprias imagens. Baixar essa imagem pro servidor?","A imagem foi enviada com sucesso para o servidor!","Palette","Não há arquivos nesse diretório.","Húngara","Digite um novo nome","preview","Baixar","Colar da área de transferência","O seu navegador não oferece suporte a acesso direto para a área de transferência.","Selecção de cópia","cópia","Border radius","Mostrar todos os","Aplicar","Por favor, preencha este campo","Por favor introduza um endereço web","Padrão","Círculo","Ponto","Quadro","Encontrar","Encontrar Anteriores","Localizar Próxima","O conteúdo colado veio de um documento Microsoft Word/Excel. Você deseja manter o formato ou limpa-lo?","Colado do Word Detectado","Limpar","Insira o nome da classe","Pressione Alt para redimensionamento personalizado"]},28359(t){t.exports.default=["Напишите что-либо","О Jodit","Редактор Jodit","Jodit Руководство пользователя","содержит детальную информацию по использованию","Для получения сведений о лицензии , пожалуйста, перейдите на наш сайт:","Купить полную версию","Авторские права © XDSoft.net - Чупурнов Валерий. Все права защищены.","Анкор","Открывать ссылку в новой вкладке","Открыть редактор в полном размере","Очистить форматирование","Цвет заливки или цвет текста","Повтор","Отмена","Жирный","Наклонный","Вставка маркированного списка","Вставить нумерованный список","Выровнять по центру","Выровнять по ширине","Выровнять по левому краю","Выровнять по правому краю","Вставить горизонтальную линию","Вставить изображение","Вставить файл","Вставьте видео","Вставить ссылку","Размер шрифта","Шрифт","Вставить блочный элемент","Нормальный текст","Заголовок 1","Заголовок 2","Заголовок 3","Заголовок 4","Цитата","Код","Вставить","Вставить таблицу","Уменьшить отступ","Увеличить отступ","Выберите специальный символ","Вставить специальный символ","Формат краски","Источник","Отступы","сверху","справа","снизу","слева","Стили","Классы","Выравнивание","По правому краю","По центру","По левому краю","--не устанавливать--","src","Заголовок","Альтернативный текст (alt)","Ссылка","Открывать ссылку в новом окне",null,"Файл","Расширенные","Свойства изображения","Отмена","Ок","Браузер файлов","Ошибка при загрузке списка изображений","Ошибка при загрузке списка директорий","Вы уверены?","Введите название директории","Создать директорию","введите название","Перетащите сюда изображение","Перетащите сюда файл","или нажмите","Альтернативный текст","Загрузка","Сервер","Фон","Текст"," К верху","По середине","К низу","Вставить столбец до","Вставить столбец после","Вставить ряд выше","Вставить ряд ниже","Удалить таблицу","Удалять ряд","Удалить столбец","Очистить ячейку","Символов: %d","Слов: %d","Перечеркнуть","Подчеркивание","верхний индекс","индекс","Вырезать","Выделить все","Разделитель","Найти","Заменить на","Заменить","Вставить","Выбрать контент для вставки","HTML","жирный","курсив","заливка","ссылка","отменить","повторить","таблица","Изображение","очистить","параграф","размер шрифта","видео","шрифт","о редакторе","печать","подчеркнутый","перечеркнутый","отступ","выступ","во весь экран","обычный размер","линия","Список","Нумерованный список","Вырезать","Выделить все","Код","Открыть ссылку","Редактировать ссылку","Атрибут nofollow","Убрать ссылку","Обновить","Редактировать","Просмотр","URL","Редактировать","Горизонтальное выравнивание","Фильтр","По изменению","По имени","По размеру","Добавить папку","Восстановить","Сохранить","Сохранить как","Изменить размер","Обрезать размер","Ширина","Высота","Сохранять пропорции","Да","Нет","Удалить","Выделить","Выделить: %s","Вертикальное выравнивание","Разделить","Объединить в одну","Добавить столбец","Добавить строку","Лицензия: %s","Удалить","Разделить по вертикали","Разделить по горизонтали","Рамка","Ваш текст, который вы пытаетесь вставить похож на HTML. Вставить его как HTML?","Вставить как HTML?","Сохранить оригинал","Вставить как текст","Вставить только текст","Вы можете редактировать только свои собственные изображения. Загрузить это изображение на ваш сервер?","Изображение успешно загружено на сервер!","палитра","В данном каталоге нет файлов","Переименовать","Введите новое имя","Предпросмотр","Скачать","Вставить из буфера обмена","Ваш браузер не поддерживает прямой доступ к буферу обмена.","Скопировать выделенное","копия","Радиус границы","Показать все","Применить","Пожалуйста, заполните это поле","Пожалуйста, введите веб-адрес","По умолчанию","Круг","Точка","Квадрат","Найти","Найти Предыдущие","Найти Далее","Контент который вы вставляете поступает из документа Microsoft Word / Excel. Вы хотите сохранить формат или очистить его?","Возможно это фрагмент Word или Excel","Почистить","Вставить название класса","Нажмите Alt для изменения пользовательского размера"]},68368(t){t.exports.default=["Bir şeyler yaz","Jodit Hakkında","Jodit Editor","Jodit Kullanım Kılavuzu","kullanım için detaylı bilgiler içerir","Lisans hakkında bilgi için lütfen web sitemize gidin:","Tam versiyonunu satın al","Copyright © XDSoft.net - Chupurnov Valeriy. Tüm hakları saklıdır.","Bağlantı","Yeni sekmede aç","Editörü tam ekranda aç","Stili temizle","Renk doldur veya yazı rengi seç","Yinele","Geri Al","Kalın","İtalik","Sırasız Liste Ekle","Sıralı Liste Ekle","Ortala","Kenarlara Yasla","Sola Yasla","Sağa Yasla","Yatay Çizgi Ekle","Resim Ekle","Dosya Ekle","Youtube/Vimeo Videosu Ekle","Bağlantı Ekle","Font Boyutu","Font Ailesi","Blok Ekle","Normal","Başlık 1","Başlık 2","Başlık 3","Başlık 4","Alıntı","Kod","Ekle","Tablo Ekle","Girintiyi Azalt","Girintiyi Arttır","Özel Karakter Seç","Özel Karakter Ekle","Resim Biçimi","Mod Değiştir","Boşluklar","Üst","Sağ","Alt","Sol","CSS Stilleri","CSS Sınıfları","Hizalama","Sağ","Ortalı","Sol","Belirsiz","Kaynak","Başlık","Alternatif Yazı","Link","Bağlantıyı yeni sekmede aç","Resim","Dosya","Gelişmiş","Resim özellikleri","İptal","Tamam","Dosya Listeleyici","Liste yüklenirken hata oluştu","Klasörler yüklenirken hata oluştur","Emin misiniz?","Dizin yolu giriniz","Dizin oluştur","İsim yaz","Resim bırak","Dosya bırak","veya tıkla","Alternatif yazı","Yükle","Gözat","Arka plan","Yazı","Üst","Orta","Aşağı","Öncesine kolon ekle","Sonrasına kolon ekle","Üstüne satır ekle","Altına satır ekle","Tabloyu sil","Satırı sil","Kolonu sil","Hücreyi temizle","Harfler: %d","Kelimeler: %d","Üstü çizili","Alt çizgi","Üst yazı","Alt yazı","Seçilimi kes","Tümünü seç","Satır sonu","Ara","Şununla değiştir","Değiştir","Yapıştır","Yapıştırılacak içerik seç","Kaynak","Kalın","italik","Fırça","Bağlantı","Geri al","Yinele","Tablo","Resim","Silgi","Paragraf","Font boyutu","Video","Font","Hakkında","Yazdır","Alt çizgi","Üstü çizili","Girinti","Çıkıntı","Tam ekran","Küçült","Ayraç","Sırasız liste","Sıralı liste","Kes","Tümünü seç","Kod ekle","Bağlantıyı aç","Bağlantıyı düzenle","Nofollow özelliği","Bağlantıyı kaldır","Güncelle","Düzenlemek için","Yorumu","URL","Düzenle","Yatay hizala","Filtre","Değişime göre sırala","İsme göre sırala","Boyuta göre sırala","Klasör ekle","Sıfırla","Kaydet","Farklı kaydet","Boyutlandır","Kırp","Genişlik","Yükseklik","En boy oranını koru","Evet","Hayır","Sil","Seç","Seç: %s","Dikey hizala","Ayır","Birleştir","Kolon ekle","Satır ekle",null,"Sil","Dikey ayır","Yatay ayır","Kenarlık","Kodunuz HTML koduna benziyor. HTML olarak devam etmek ister misiniz?","HTML olarak yapıştır","Sakla","Yazı olarak ekle","Sadece yazıyı ekle","Sadece kendi resimlerinizi düzenleyebilirsiniz. Bu görseli kendi hostunuza indirmek ister misiniz?","Görsel başarıyla hostunuza yüklendi","Palet","Bu dizinde dosya yok","Yeniden isimlendir","Yeni isim girin","Ön izleme","İndir","Panodan yapıştır ","Tarayıcınız panoya doğrudan erişimi desteklemiyor.","Seçimi kopyala","Kopyala","Sınır yarıçapı","Tümünü Göster","Uygula","Lütfen bu alanı doldurun","Lütfen bir web adresi girin","Varsayılan","Daire","Nokta","Kare","Bul","Öncekini Bul","Sonrakini Bul","Der Inhalt, den Sie einfügen, stammt aus einem Microsoft Word / Excel-Dokument. Möchten Sie das Format erhalten oder löschen?","Word biçiminde yapıştırma algılandı","Temizle","Sınıf adı girin","Özel yeniden boyutlandırma için Alt tuşuna basın"]},25182(t){t.exports.default=["输入一些内容","关于Jodit","Jodit Editor","开发者指南","使用帮助","有关许可证的信息,请访问我们的网站:","购买完整版本","Copyright © XDSoft.net - Chupurnov Valeriy. 版权所有","Anchor","在新窗口打开","全屏编辑","清除样式","颜色","重做","撤销","粗体","斜体","符号列表","编号","居中","对齐文本","左对齐","右对齐","分割线","图片","文件","视频","链接","字号","字体","格式块","默认","标题1","标题2","标题3","标题4","引用","代码","插入","表格","减少缩进","增加缩进","选择特殊符号","特殊符号","格式复制","改变模式","外边距(Margins)","top","right","bottom","left","样式","Classes","对齐方式","居右","居中","居左","无","Src","Title","Alternative","Link","在新窗口打开链接","图片","file","高级","图片属性","取消","确定","文件管理","加载list错误","加载folders错误","你确定吗?","输入路径","创建路径","type name","拖动图片到此","拖动文件到此","或点击","Alternative text","上传","浏览","背景色","文字","顶部","中间","底部","在之前插入列","在之后插入列","在之前插入行","在之后插入行","删除表格","删除行","删除列","清除内容","字符数: %d","单词数: %d","删除线","下划线","上标","下标","剪切","全选","Break","查找","替换为","替换","粘贴","选择内容并粘贴","源码","粗体","斜体","颜色","链接","撤销","重做","表格","图片","橡皮擦","段落","字号","视频","字体","关于","打印","下划线","上出现","增加缩进","减少缩进","全屏","收缩","分割线","无序列表","顺序列表","剪切","全选","嵌入代码","打开链接","编辑链接","No follow","取消链接","更新","铅笔","预览","URL","编辑","水平对齐","筛选","修改时间排序","名称排序","大小排序","新建文件夹","重置","保存","保存为","调整大小","剪切","宽","高","保持长宽比","是","不","移除","选择","选择: %s","垂直对齐","拆分","合并","添加列","添加行",null,"删除","垂直拆分","水平拆分","边框","你粘贴的文本是一段html代码,是否保留源格式","html粘贴","保留源格式","把html代码视为普通文本","只保留文本","你只能编辑你自己的图片。Download this image on the host?","图片上传成功","调色板","此目录中沒有文件。","重命名","输入新名称","预览","下载","粘贴从剪贴板","你浏览器不支持直接访问的剪贴板。","复制选中内容","复制","边界半径","显示所有","应用","请填写这个字段","请输入一个网址","默认","圆圈","点","方形","搜索","查找上一个","查找下一个","正在粘贴 Word/Excel 的文本,是否保留源格式?","文本粘贴","匹配目标格式","插入班级名称","按Alt自定义调整大小"]},44906(t){t.exports.default=["輸入一些內容","關於Jodit","Jodit Editor","開發者指南","使用幫助","相關授權條款資訊,請造訪我們的網站:","購買完整版本","Copyright © XDSoft.net - Chupurnov Valeriy. All rights reserved.","錨點","在新分頁開啟","全螢幕編輯","清除樣式","顏色","取消復原","復原","粗體","斜體","項目符號清單","編號清單","置中","文字對齊","靠左","靠右","分割線","圖片","檔案","插入 youtube/vimeo 影片","插入連結","文字大小","字型","格式化區塊","內文","標題1","標題2","標題3","標題4","引文","程式碼","插入","表格","減少縮排","增加縮排","選擇特殊符號","特殊符號","格式複製","檢視原始碼","邊距","上","右","下","左","樣式","Classes","對齊方式","靠右","置中","靠左","無","Src","Title","替代","Link","在新分頁開啟連結","圖片","檔案","進階","圖片屬性","取消","確定","檔案瀏覽","清單載入錯誤","資料夾載入錯誤","您確定嗎?","輸入路徑","創建路徑","type name","拖曳圖片至此","拖曳檔案至此","或點擊","替代文字","上傳","瀏覽","背景色","文字","頂部","中間","底部","插入左方欄","插入右方欄","插入上方列","插入下方列","刪除表格","刪除整列","刪除整欄","清除內容","字元數: %d","單字數: %d","刪除線","底線","上標","下標","剪下","全選","斷行","尋找","取代為","取代","貼上","選擇內容並貼上","原始碼","粗體","斜體","顏色","連結","復原","取消復原","表格","圖片","橡皮擦","段落","文字大小","影片","字型","關於","列印","底線","刪除線","增加縮排","減少縮排","全螢幕","縮減","分隔線","項目符號清單","編號清單","剪下","全選","嵌入程式碼","打開連結","編輯連結","No follow","取消連結","更新","鉛筆","查看","URL",null,"水平對齊","篩選","修改時間排序","名稱排序","大小排序","新增資料夾","重設","儲存","另存為...","調整大小","裁切","寬","高","維持長寬比","是","否","移除","選擇","選擇: %s","垂直對齊","分割","合併","新增欄","新增列",null,"刪除","垂直分割","水平分割","邊框","您的程式碼與 HTML 類似,是否貼上 HTML 格式?","貼上 HTML","保留原始格式","以純文字貼上","僅貼上內文","您只能編輯您自己的圖片。是否下載此圖片?","圖片上傳成功","調色盤","沒有檔案","重新命名","輸入新名稱","預覽","下載","從剪貼簿貼上","瀏覽器無法存取剪貼簿。","複製已選取項目","複製","邊框圓角","顯示全部","應用","請輸入此欄位","請輸入網址","預設","圓圈","點","方形","尋找","尋找上一個","尋找下一個","正在貼上 Word/Excel 文件的內容,是否保留原始格式?","貼上 Word 格式","清除格式","插入 class 名稱","按住 Alt 以調整自訂大小"]},928(t){t.exports=' '},31230(t){t.exports=' '},54522(t){t.exports=' '},17995(t){t.exports=' '},86634(t){t.exports=' '},91115(t){t.exports=' '},1916(t){t.exports=' '},52450(t){t.exports=' '},41111(t){t.exports=' '},49972(t){t.exports=' '},45062(t){t.exports=' '},18605(t){t.exports=' '},83389(t){t.exports=' '},93267(t){t.exports=' '},71948(t){t.exports=' '},51457(t){t.exports=' '},23602(t){t.exports=' '},86899(t){t.exports=' '},95320(t){t.exports=' '},45674(t){t.exports=' '},3843(t){t.exports=' '},48842(t){t.exports=' '},25501(t){t.exports=' '},29348(t){t.exports=''},24772(t){t.exports=' '},66547(t){t.exports=' '},89097(t){t.exports=' '},64831(t){t.exports=' '},67176(t){t.exports=' '},14017(t){t.exports=' '},38681(t){t.exports=' '},64637(t){t.exports=' '},94190(t){t.exports=' '},51957(t){t.exports=' '},71940(t){t.exports=' '},48007(t){t.exports=' '},43218(t){t.exports=' '},80515(t){t.exports=' '},223(t){t.exports=' '},95032(t){t.exports=' '},73533(t){t.exports=' '},40037(t){t.exports=' '},83207(t){t.exports=' '},59827(t){t.exports=' '},34045(t){t.exports=' '},39199(t){t.exports=' '},21917(t){t.exports=' '},9103(t){t.exports=' '},49989(t){t.exports=' '},81875(t){t.exports=' '},67447(t){t.exports=' '},36339(t){t.exports=' '},88497(t){t.exports=' '},91882(t){t.exports=' '},14305(t){t.exports=' '},58446(t){t.exports=' '},39858(t){t.exports=' '},70881(t){t.exports=' '},60636(t){t.exports=' '},32013(t){t.exports=' '},45512(t){t.exports=' '},80347(t){t.exports=' '},95134(t){t.exports=' '},70697(t){t.exports=' '},49983(t){t.exports=' '},98964(t){t.exports=' '},8136(t){t.exports=' '},94806(t){t.exports=''},31365(t){t.exports=' '},44636(t){t.exports=''},36327(t){t.exports=''},53328(t){t.exports=' '},98711(t){t.exports=' '},53808(t){t.exports=' '},20784(t){t.exports=' '},70999(t){t.exports=' '},45244(t){t.exports=' '},99876(t){t.exports=' '},14006(t){t.exports=' '},28712(t){"use strict";t.exports={assert(){}}},31635(t,e,s){"use strict";function i(t,e,s,i){var r,o=arguments.length,n=3>o?e:null===i?i=Object.getOwnPropertyDescriptor(e,s):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)n=Reflect.decorate(t,e,s,i);else for(var a=t.length-1;a>=0;a--)(r=t[a])&&(n=(3>o?r(n):o>3?r(e,s,n):r(e,s))||n);return o>3&&n&&Object.defineProperty(e,s,n),n}s.d(e,{Cg(){return i}}),"function"==typeof SuppressedError&&SuppressedError}},s={};function i(t){var r=s[t];if(void 0!==r)return r.exports;var o=s[t]={exports:{}};return e[t](o,o.exports,i),o.exports}i.m=e,t=[],i.O=(e,s,r,o)=>{if(!s){var n=1/0;for(u=0;t.length>u;u++){s=t[u][0],r=t[u][1],o=t[u][2];for(var a=!0,l=0;s.length>l;l++)(!1&o||n>=o)&&Object.keys(i.O).every((t=>i.O[t](s[l])))?s.splice(l--,1):(a=!1,n>o&&(n=o));if(a){t.splice(u--,1);var c=r();void 0!==c&&(e=c)}}return e}o=o||0;for(var u=t.length;u>0&&t[u-1][2]>o;u--)t[u]=t[u-1];t[u]=[s,r,o]},i.n=t=>{var e=t&&t.__esModule?()=>t.default:()=>t;return i.d(e,{a:e}),e},i.d=(t,e)=>{for(var s in e)i.o(e,s)&&!i.o(t,s)&&Object.defineProperty(t,s,{enumerable:!0,get:e[s]})},i.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),i.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},(()=>{var t={521:0};i.O.j=e=>0===t[e];var e=(e,s)=>{var r,o,n=s[0],a=s[1],l=s[2],c=0;if(n.some((e=>0!==t[e]))){for(r in a)i.o(a,r)&&(i.m[r]=a[r]);if(l)var u=l(i)}for(e&&e(s);n.length>c;c++)i.o(t,o=n[c])&&t[o]&&t[o][0](),t[o]=0;return i.O(u)},s=self.webpackChunkjodit=self.webpackChunkjodit||[];s.forEach(e.bind(null,0)),s.push=e.bind(null,s.push.bind(s))})();var r={};return(()=>{"use strict";i.r(r),i.d(r,{CommitMode(){return u},Jodit(){return a.x}});var t=i(9823),e=(i(88222),i(17352)),s=i(22664),o=i(37435),n=i(79721),a=i(46173),l=i(74470);Object.keys(e).forEach((t=>{a.x[t]=e[t]}));const c=t=>"__esModule"!==t;Object.keys(n).filter(c).forEach((t=>{o.Icon.set(t.replace("_","-"),n[t])})),Object.keys(o).filter(c).forEach((e=>{const s=o[e],i=(0,t.Tn)(s.prototype?.className)?s.prototype.className():e;(0,t.Kg)(i)&&(a.x.modules[i]=s)})),Object.keys(s).filter(c).forEach((t=>{a.x.decorators[t]=s[t]})),["Confirm","Alert","Prompt"].forEach((t=>{a.x[t]=o[t]})),Object.keys(l.A).filter(c).forEach((t=>{a.x.lang[t]=l.A[t]}));class u{}})(),i.O(r)}()})); diff --git a/Wino.Mail.WinUI/JS/reader.html b/Wino.Mail.WinUI/JS/reader.html new file mode 100644 index 00000000..e2a43ac6 --- /dev/null +++ b/Wino.Mail.WinUI/JS/reader.html @@ -0,0 +1,51 @@ + + + + + + + + + +
+ + diff --git a/Wino.Mail.WinUI/MainWindow.xaml b/Wino.Mail.WinUI/MainWindow.xaml deleted file mode 100644 index f2224366..00000000 --- a/Wino.Mail.WinUI/MainWindow.xaml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - diff --git a/Wino.Mail.WinUI/MainWindow.xaml.cs b/Wino.Mail.WinUI/MainWindow.xaml.cs deleted file mode 100644 index 2cc21a35..00000000 --- a/Wino.Mail.WinUI/MainWindow.xaml.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices.WindowsRuntime; -using Microsoft.UI.Xaml; -using Microsoft.UI.Xaml.Controls; -using Microsoft.UI.Xaml.Controls.Primitives; -using Microsoft.UI.Xaml.Data; -using Microsoft.UI.Xaml.Input; -using Microsoft.UI.Xaml.Media; -using Microsoft.UI.Xaml.Navigation; -using Windows.Foundation; -using Windows.Foundation.Collections; - -// To learn more about WinUI, the WinUI project structure, -// and more about our project templates, see: http://aka.ms/winui-project-info. - -namespace Wino.Mail.WinUI -{ - /// - /// An empty window that can be used on its own or navigated to within a Frame. - /// - public sealed partial class MainWindow : Window - { - public MainWindow() - { - this.InitializeComponent(); - } - - private void myButton_Click(object sender, RoutedEventArgs e) - { - myButton.Content = "Clicked"; - } - } -} diff --git a/Wino.Mail.WinUI/MenuFlyouts/AccountSelectorFlyout.cs b/Wino.Mail.WinUI/MenuFlyouts/AccountSelectorFlyout.cs new file mode 100644 index 00000000..4d3ab259 --- /dev/null +++ b/Wino.Mail.WinUI/MenuFlyouts/AccountSelectorFlyout.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +using Wino.Controls; +using Wino.Core.Domain.Entities; +using Wino.Helpers; + +#if NET8_0 +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml; +#else +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml; +#endif + +namespace Wino.MenuFlyouts +{ + public class AccountSelectorFlyout : MenuFlyout, IDisposable + { + private readonly IEnumerable _accounts; + private readonly Func _onItemSelection; + + public AccountSelectorFlyout(IEnumerable accounts, Func onItemSelection) + { + _accounts = accounts; + _onItemSelection = onItemSelection; + + foreach (var account in _accounts) + { + var pathData = new WinoFontIcon() { Icon = XamlHelpers.GetProviderIcon(account.ProviderType) }; + var menuItem = new MenuFlyoutItem() { Tag = account.Address, Icon = pathData, Text = $"{account.Name} ({account.Address})", MinHeight = 55 }; + + menuItem.Click += AccountClicked; + Items.Add(menuItem); + } + } + + public void Dispose() + { + foreach (var menuItem in Items) + { + if (menuItem is MenuFlyoutItem flyoutItem) + { + flyoutItem.Click -= AccountClicked; + } + } + } + + private async void AccountClicked(object sender, RoutedEventArgs e) + { + if (sender is MenuFlyoutItem menuItem && menuItem.Tag is string accountAddress) + { + var selectedMenuItem = _accounts.FirstOrDefault(a => a.Address == accountAddress); + + if (selectedMenuItem != null) + { + await _onItemSelection(selectedMenuItem); + } + } + + Dispose(); + Hide(); + } + } +} diff --git a/Wino.Mail.WinUI/MenuFlyouts/FilterMenuFlyout.cs b/Wino.Mail.WinUI/MenuFlyouts/FilterMenuFlyout.cs new file mode 100644 index 00000000..6901dca3 --- /dev/null +++ b/Wino.Mail.WinUI/MenuFlyouts/FilterMenuFlyout.cs @@ -0,0 +1,225 @@ +using System.Collections.Generic; +using System.Linq; +using CommunityToolkit.Mvvm.Input; +using Wino.Controls; +using Wino.Core.Domain.Models.Reader; +using Wino.Helpers; + +#if NET8_0 +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml; +#else +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml; +#endif +namespace Wino.MenuFlyouts +{ + public class FilterMenuFlyout : MenuFlyout + { + public static readonly DependencyProperty SelectedFilterChangedCommandProperty = DependencyProperty.Register(nameof(SelectedFilterChangedCommand), typeof(IRelayCommand), typeof(FilterMenuFlyout), new PropertyMetadata(null)); + public static readonly DependencyProperty FilterOptionsProperty = DependencyProperty.Register(nameof(FilterOptions), typeof(List), typeof(FilterMenuFlyout), new PropertyMetadata(null, new PropertyChangedCallback(OnOptionsChanged))); + public static readonly DependencyProperty SelectedFilterOptionProperty = DependencyProperty.Register(nameof(SelectedFilterOption), typeof(FilterOption), typeof(FilterMenuFlyout), new PropertyMetadata(null, OnSelectedFilterOptionChanged)); + public static readonly DependencyProperty SelectedSortingOptionProperty = DependencyProperty.Register(nameof(SelectedSortingOption), typeof(SortingOption), typeof(FilterMenuFlyout), new PropertyMetadata(null, new PropertyChangedCallback(OnSelectedSortingOptionChanged))); + public static readonly DependencyProperty SortingOptionsProperty = DependencyProperty.Register(nameof(SortingOptions), typeof(List), typeof(FilterMenuFlyout), new PropertyMetadata(null, new PropertyChangedCallback(OnOptionsChanged))); + public static readonly DependencyProperty SelectedSortingOptionChangedCommandProperty = DependencyProperty.Register(nameof(SelectedSortingOptionChangedCommand), typeof(IRelayCommand), typeof(FilterMenuFlyout), new PropertyMetadata(null)); + + public IRelayCommand SelectedFilterChangedCommand + { + get { return (IRelayCommand)GetValue(SelectedFilterChangedCommandProperty); } + set { SetValue(SelectedFilterChangedCommandProperty, value); } + } + + public IRelayCommand SelectedSortingOptionChangedCommand + { + get { return (IRelayCommand)GetValue(SelectedSortingOptionChangedCommandProperty); } + set { SetValue(SelectedSortingOptionChangedCommandProperty, value); } + } + + public List FilterOptions + { + get { return (List)GetValue(FilterOptionsProperty); } + set { SetValue(FilterOptionsProperty, value); } + } + + public List SortingOptions + { + get { return (List)GetValue(SortingOptionsProperty); } + set { SetValue(SortingOptionsProperty, value); } + } + + public FilterOption SelectedFilterOption + { + get { return (FilterOption)GetValue(SelectedFilterOptionProperty); } + set { SetValue(SelectedFilterOptionProperty, value); } + } + + public SortingOption SelectedSortingOption + { + get { return (SortingOption)GetValue(SelectedSortingOptionProperty); } + set { SetValue(SelectedSortingOptionProperty, value); } + } + + private static void OnSelectedFilterOptionChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) + { + if (obj is FilterMenuFlyout bar) + { + bar.SelectFilterOption(bar.SelectedFilterOption); + bar.SelectedFilterChangedCommand?.Execute(bar.SelectedFilterOption); + } + } + + private static void OnSelectedSortingOptionChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) + { + if (obj is FilterMenuFlyout bar) + { + bar.SelectSortingOption(bar.SelectedSortingOption); + bar.SelectedSortingOptionChangedCommand?.Execute(bar.SelectedSortingOption); + } + } + + private ToggleMenuFlyoutItem CreateFilterToggleButton(FilterOption option) + { + var button = new ToggleMenuFlyoutItem() + { + Text = option.Title, + Tag = option, + Icon = new WinoFontIcon() { Icon = XamlHelpers.GetWinoIconGlyph(option.Type) }, + IsChecked = option == SelectedFilterOption + }; + + button.Click += FilterToggleChecked; + + return button; + } + + private ToggleMenuFlyoutItem CreateSortingToggleButton(SortingOption option) + { + var button = new ToggleMenuFlyoutItem() + { + Text = option.Title, + Tag = option, + IsChecked = option == SelectedSortingOption + }; + + button.Click += SortingOptionChecked; + + return button; + } + + private void SortingOptionChecked(object sender, RoutedEventArgs e) + { + if (sender is ToggleMenuFlyoutItem button) + { + button.IsHitTestVisible = false; + + var optionModel = button.Tag as SortingOption; + + SelectSortingOption(optionModel); + } + } + + + + private void FilterToggleChecked(object sender, RoutedEventArgs e) + { + if (sender is ToggleMenuFlyoutItem button) + { + button.IsHitTestVisible = false; + + var optionModel = button.Tag as FilterOption; + + SelectFilterOption(optionModel); + } + } + + private void SelectFilterOption(FilterOption option) + { + SelectedFilterOption = option; + + UncheckOtherFilterOptions(); + } + + private void SelectSortingOption(SortingOption option) + { + SelectedSortingOption = option; + + UncheckOtherSortingOptions(); + } + + private void UnregisterCheckedHandler(ToggleMenuFlyoutItem button) + { + button.Click -= FilterToggleChecked; + } + + private void UncheckOtherFilterOptions() + { + if (Items.Any()) + { + foreach (var item in Items) + { + if (item is ToggleMenuFlyoutItem toggleButton && toggleButton.Tag is FilterOption option && option != SelectedFilterOption) + { + toggleButton.IsChecked = false; + toggleButton.IsHitTestVisible = true; + } + } + } + } + + private void UncheckOtherSortingOptions() + { + if (Items.Any()) + { + foreach (var item in Items) + { + if (item is ToggleMenuFlyoutItem toggleButton && toggleButton.Tag is SortingOption option && option != SelectedSortingOption) + { + toggleButton.IsChecked = false; + toggleButton.IsHitTestVisible = true; + } + } + } + } + + public void Dispose() + { + foreach (var item in Items) + { + if (item is ToggleMenuFlyoutItem toggleButton) + { + UnregisterCheckedHandler(toggleButton); + } + } + } + + private static void OnOptionsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) + { + if (obj is FilterMenuFlyout bar && bar.SortingOptions != null && bar.FilterOptions != null) + { + bar.Dispose(); + + bar.Items.Clear(); + + if (bar.FilterOptions != null) + { + foreach (var item in bar.FilterOptions) + { + bar.Items.Add(bar.CreateFilterToggleButton(item)); + } + } + + bar.Items.Add(new MenuFlyoutSeparator()); + + // Sorting options. + + if (bar.SortingOptions != null) + { + foreach (var item in bar.SortingOptions) + { + bar.Items.Add(bar.CreateSortingToggleButton(item)); + } + } + } + } + } +} diff --git a/Wino.Mail.WinUI/MenuFlyouts/FolderOperationFlyout.cs b/Wino.Mail.WinUI/MenuFlyouts/FolderOperationFlyout.cs new file mode 100644 index 00000000..69482907 --- /dev/null +++ b/Wino.Mail.WinUI/MenuFlyouts/FolderOperationFlyout.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +using Wino.Core.Domain.Enums; +using Wino.Core.Domain.Models.Folders; + +#if NET8_0 +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml.Controls; +#endif + +namespace Wino.MenuFlyouts.Context +{ + public class FolderOperationFlyout : WinoOperationFlyout + { + public FolderOperationFlyout(IEnumerable availableActions, TaskCompletionSource completionSource) : base(availableActions, completionSource) + { + if (AvailableActions == null) return; + + foreach (var action in AvailableActions) + { + if (action.Operation == FolderOperation.Seperator) + Items.Add(new MenuFlyoutSeparator()); + else + { + var menuFlyoutItem = new FolderOperationMenuFlyoutItem(action, (c) => MenuItemClicked(c)); + + Items.Add(menuFlyoutItem); + } + } + } + } +} diff --git a/Wino.Mail.WinUI/MenuFlyouts/FolderOperationMenuFlyoutItem.cs b/Wino.Mail.WinUI/MenuFlyouts/FolderOperationMenuFlyoutItem.cs new file mode 100644 index 00000000..c6b788c6 --- /dev/null +++ b/Wino.Mail.WinUI/MenuFlyouts/FolderOperationMenuFlyoutItem.cs @@ -0,0 +1,12 @@ +using System; +using Wino.Core.Domain.Models.Folders; + +namespace Wino.MenuFlyouts +{ + public class FolderOperationMenuFlyoutItem : WinoOperationFlyoutItem + { + public FolderOperationMenuFlyoutItem(FolderOperationMenuItem operationMenuItem, Action clicked) : base(operationMenuItem, clicked) + { + } + } +} diff --git a/Wino.Mail.WinUI/MenuFlyouts/MailOperationFlyout.cs b/Wino.Mail.WinUI/MenuFlyouts/MailOperationFlyout.cs new file mode 100644 index 00000000..83a89954 --- /dev/null +++ b/Wino.Mail.WinUI/MenuFlyouts/MailOperationFlyout.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using System.Threading.Tasks; + +using Wino.Core.Domain.Enums; +using Wino.Core.Domain.Models.Menus; + + +#if NET8_0 +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml.Controls; +#endif +namespace Wino.MenuFlyouts.Context +{ + public class MailOperationFlyout : WinoOperationFlyout + { + public MailOperationFlyout(IEnumerable availableActions, TaskCompletionSource completionSource) : base(availableActions, completionSource) + { + if (AvailableActions == null) return; + + foreach (var action in AvailableActions) + { + if (action.Operation == MailOperation.Seperator) + Items.Add(new MenuFlyoutSeparator()); + else + { + var menuFlyoutItem = new MailOperationMenuFlyoutItem(action, (c) => MenuItemClicked(c)); + + Items.Add(menuFlyoutItem); + } + } + } + } +} diff --git a/Wino.Mail.WinUI/MenuFlyouts/MailOperationMenuFlyoutItem.cs b/Wino.Mail.WinUI/MenuFlyouts/MailOperationMenuFlyoutItem.cs new file mode 100644 index 00000000..51c1953b --- /dev/null +++ b/Wino.Mail.WinUI/MenuFlyouts/MailOperationMenuFlyoutItem.cs @@ -0,0 +1,12 @@ +using System; +using Wino.Core.Domain.Models.Menus; + +namespace Wino.MenuFlyouts.Context +{ + public class MailOperationMenuFlyoutItem : WinoOperationFlyoutItem + { + public MailOperationMenuFlyoutItem(MailOperationMenuItem operationMenuItem, Action clicked) : base(operationMenuItem, clicked) + { + } + } +} diff --git a/Wino.Mail.WinUI/MenuFlyouts/MoveButtonFlyout.cs b/Wino.Mail.WinUI/MenuFlyouts/MoveButtonFlyout.cs new file mode 100644 index 00000000..c7d737b8 --- /dev/null +++ b/Wino.Mail.WinUI/MenuFlyouts/MoveButtonFlyout.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Windows.Foundation; +using Wino.Core.Domain.Entities; + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +#endif + +namespace Wino.MenuFlyouts +{ + public class MoveButtonMenuItemClickedEventArgs + { + public Guid ClickedFolderId { get; set; } + } + + public class MoveButtonFlyout : MenuFlyout + { + public event TypedEventHandler MenuItemClick; + public static readonly DependencyProperty FoldersProperty = DependencyProperty.Register(nameof(Folders), typeof(List), typeof(MoveButtonFlyout), new PropertyMetadata(null, new PropertyChangedCallback(OnFoldersChanged))); + + public List Folders + { + get { return (List)GetValue(FoldersProperty); } + set { SetValue(FoldersProperty, value); } + } + + private static void OnFoldersChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) + { + if (obj is MoveButtonFlyout menu) + { + menu.InitializeMenu(); + } + + + } + + private void InitializeMenu() + { + Dispose(); + + Items.Clear(); + + if (Folders == null || !Folders.Any()) + return; + + // TODO: Child folders. + + foreach (var item in Folders) + { + // We don't expect this, but it crashes startup. + // Just to be on the safe side. + if (item.FolderName != null) + { + var folderMenuItem = new MenuFlyoutItem() + { + Tag = item, + Text = item.FolderName + }; + + folderMenuItem.Click += MenuItemClicked; + + Items.Add(folderMenuItem); + } + } + } + + private void MenuItemClicked(object sender, RoutedEventArgs e) + { + var clickedFolder = (sender as MenuFlyoutItem).Tag as MailItemFolder; + + MenuItemClick?.Invoke(this, new MoveButtonMenuItemClickedEventArgs() + { + ClickedFolderId = clickedFolder.Id + }); + } + + public void Dispose() + { + foreach (var item in Items) + { + if (item is MenuFlyoutItem menuItem) + { + menuItem.Click -= MenuItemClicked; + } + } + } + } +} diff --git a/Wino.Mail.WinUI/MenuFlyouts/RendererCommandBarItem.cs b/Wino.Mail.WinUI/MenuFlyouts/RendererCommandBarItem.cs new file mode 100644 index 00000000..1ff9eb58 --- /dev/null +++ b/Wino.Mail.WinUI/MenuFlyouts/RendererCommandBarItem.cs @@ -0,0 +1,45 @@ +using System; + +using Wino.Controls; +using Wino.Core.Domain.Enums; +using Wino.Helpers; + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +#endif +namespace Wino.MenuFlyouts +{ + public class RendererCommandBarItem : AppBarButton, IDisposable + { + public MailOperation Operation { get; set; } + Action Clicked { get; set; } + + public RendererCommandBarItem(MailOperation operation, Action clicked) + { + Margin = new Thickness(6, 0, 6, 0); + CornerRadius = new CornerRadius(6); + + Operation = operation; + Clicked = clicked; + + Label = XamlHelpers.GetOperationString(operation); + Icon = new WinoFontIcon() { Icon = WinoIconGlyph.Archive }; + + Click += MenuClicked; + } + + private void MenuClicked(object sender, RoutedEventArgs e) + { + Clicked(Operation); + } + + public void Dispose() + { + Click -= MenuClicked; + } + } +} diff --git a/Wino.Mail.WinUI/MenuFlyouts/WinoOperationFlyout.cs b/Wino.Mail.WinUI/MenuFlyouts/WinoOperationFlyout.cs new file mode 100644 index 00000000..9882ddf9 --- /dev/null +++ b/Wino.Mail.WinUI/MenuFlyouts/WinoOperationFlyout.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +#if NET8_0 +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Controls.Primitives; +#else +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Controls.Primitives; +#endif +namespace Wino.MenuFlyouts +{ + public class WinoOperationFlyout : MenuFlyout, IDisposable where TActionType : class + { + public TActionType ClickedOperation { get; set; } + + protected readonly IEnumerable AvailableActions; + + private readonly TaskCompletionSource _completionSource; + + public WinoOperationFlyout(IEnumerable availableActions, TaskCompletionSource completionSource) + { + _completionSource = completionSource; + + AvailableActions = availableActions; + + Closing += FlyoutClosing; + } + + private void FlyoutClosing(FlyoutBase sender, FlyoutBaseClosingEventArgs args) + { + Closing -= FlyoutClosing; + + _completionSource.TrySetResult(ClickedOperation); + } + + protected void MenuItemClicked(TActionType operation) + { + ClickedOperation = operation; + + Hide(); + } + + public void Dispose() + { + foreach (var item in Items) + { + if (item is IDisposable disposableItem) + { + disposableItem.Dispose(); + } + } + } + } +} diff --git a/Wino.Mail.WinUI/MenuFlyouts/WinoOperationFlyoutItem.cs b/Wino.Mail.WinUI/MenuFlyouts/WinoOperationFlyoutItem.cs new file mode 100644 index 00000000..3161f2a4 --- /dev/null +++ b/Wino.Mail.WinUI/MenuFlyouts/WinoOperationFlyoutItem.cs @@ -0,0 +1,65 @@ +using System; + +using Wino.Controls; +using Wino.Core.Domain.Interfaces; +using Wino.Core.Domain.Models.Folders; +using Wino.Core.Domain.Models.Menus; +using Wino.Helpers; + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +#endif + +namespace Wino.MenuFlyouts +{ + public class WinoOperationFlyoutItem : MenuFlyoutItem, IDisposable where TOperationMenuItem : IMenuOperation + { + private const double CustomHeight = 35; + + public TOperationMenuItem Operation { get; set; } + Action Clicked { get; set; } + + public WinoOperationFlyoutItem(TOperationMenuItem operationMenuItem, Action clicked) + { + Margin = new Thickness(4, 2, 4, 2); + CornerRadius = new CornerRadius(6, 6, 6, 6); + + MinHeight = CustomHeight; + + Operation = operationMenuItem; + IsEnabled = operationMenuItem.IsEnabled; + + if (Operation is FolderOperationMenuItem folderOperationMenuItem) + { + var internalOperation = folderOperationMenuItem.Operation; + + Icon = new WinoFontIcon() { Icon = XamlHelpers.GetPathGeometry(internalOperation) }; + Text = XamlHelpers.GetOperationString(internalOperation); + } + else if (Operation is MailOperationMenuItem mailOperationMenuItem) + { + var internalOperation = mailOperationMenuItem.Operation; + + Icon = new WinoFontIcon() { Icon = XamlHelpers.GetWinoIconGlyph(internalOperation) }; + Text = XamlHelpers.GetOperationString(internalOperation); + } + + Clicked = clicked; + Click += MenuClicked; + } + + private void MenuClicked(object sender, RoutedEventArgs e) + { + Clicked(Operation); + } + + public void Dispose() + { + Click -= MenuClicked; + } + } +} diff --git a/Wino.Mail.WinUI/PartialApp.cs b/Wino.Mail.WinUI/PartialApp.cs new file mode 100644 index 00000000..c5c80b27 --- /dev/null +++ b/Wino.Mail.WinUI/PartialApp.cs @@ -0,0 +1,163 @@ +using System; +using System.Collections.Generic; +using Microsoft.AppCenter; +using Microsoft.AppCenter.Analytics; +using Microsoft.AppCenter.Crashes; +using Microsoft.Extensions.DependencyInjection; +using Windows.ApplicationModel.Core; +using Windows.Foundation.Metadata; +using Windows.Storage; +using Windows.System.Profile; +using Windows.UI.ViewManagement; +using Wino.Activation; +using Wino.Core; +using Wino.Core.Domain.Interfaces; +using Wino.Core.UWP; +using Wino.Mail.ViewModels; +using Wino.Services; +using Wino.Core.Services; +using Windows.ApplicationModel.AppService; +using Wino.Core.UWP.Services; +using Wino.Core.WinUI.Services; + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI; +#else +using Windows.UI.Xaml; +using Windows.UI; +#endif + +namespace Wino.Mail.WinUI +{ + public partial class App : Application + { + private const string WinoLaunchLogPrefix = "[Wino Launch] "; + private const string AppCenterKey = "90deb1d0-a77f-47d0-8a6b-7eaf111c6b72"; + + + private readonly IWinoServerConnectionManager _appServiceConnectionManager; + private readonly ILogInitializer _logInitializer; + private readonly IThemeService _themeService; + private readonly IDatabaseService _databaseService; + private readonly ITranslationService _translationService; + private readonly IAppShellService _appShellService; + + public new static App Current => (App)Application.Current; + public IServiceProvider Services { get; } + + // Order matters. + private List initializeServices => new List() + { + _databaseService, + _translationService, + _themeService, + }; + + private IServiceProvider ConfigureServices() + { + var services = new ServiceCollection(); + + services.RegisterCoreServices(); + services.RegisterCoreUWPServices(); + + RegisterUWPServices(services); + RegisterViewModels(services); + RegisterActivationHandlers(services); + + return services.BuildServiceProvider(); + } + + #region Misc Configuration + + private void ConfigureLogger() => _logInitializer.SetupLogger(ApplicationData.Current.LocalFolder.Path); + + private void ConfigureAppCenter() => AppCenter.Start(AppCenterKey, typeof(Analytics), typeof(Crashes)); + + private void ConfigurePrelaunch() + { + if (ApiInformation.IsMethodPresent("Windows.ApplicationModel.Core.CoreApplication", "EnablePrelaunch")) + CoreApplication.EnablePrelaunch(true); + } + + private void ConfigureXbox() + { + // Xbox users should use Reveal focus. + if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 6)) + { + FocusVisualKind = AnalyticsInfo.VersionInfo.DeviceFamily == "Xbox" ? FocusVisualKind.Reveal : FocusVisualKind.HighVisibility; + } + } + + private void ConfigureTitleBar() + { + var coreTitleBar = CoreApplication.GetCurrentView().TitleBar; + var applicationViewTitleBar = ApplicationView.GetForCurrentView().TitleBar; + + // Extend shell content into core window to meet design requirements. + coreTitleBar.ExtendViewIntoTitleBar = true; + + // Change system buttons and background colors to meet design requirements. + applicationViewTitleBar.ButtonBackgroundColor = Colors.Transparent; + applicationViewTitleBar.BackgroundColor = Colors.Transparent; + applicationViewTitleBar.ButtonInactiveBackgroundColor = Colors.Transparent; + applicationViewTitleBar.ButtonForegroundColor = Colors.White; + } + + #endregion + + #region Dependency Injection + + private void RegisterActivationHandlers(IServiceCollection services) + { + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + } + + private void RegisterUWPServices(IServiceCollection services) + { + services.AddSingleton, ApplicationResourceManager>(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + } + + private void RegisterViewModels(IServiceCollection services) + { + services.AddSingleton(typeof(AppShellViewModel)); + services.AddTransient(typeof(SettingsDialogViewModel)); + services.AddTransient(typeof(PersonalizationPageViewModel)); + services.AddTransient(typeof(SettingOptionsPageViewModel)); + services.AddTransient(typeof(MailListPageViewModel)); + services.AddTransient(typeof(MailRenderingPageViewModel)); + services.AddTransient(typeof(AccountManagementViewModel)); + services.AddTransient(typeof(WelcomePageViewModel)); + services.AddTransient(typeof(AboutPageViewModel)); + services.AddTransient(typeof(ComposePageViewModel)); + services.AddTransient(typeof(IdlePageViewModel)); + services.AddTransient(typeof(SettingsPageViewModel)); + services.AddTransient(typeof(NewAccountManagementPageViewModel)); + services.AddTransient(typeof(AccountDetailsPageViewModel)); + services.AddTransient(typeof(SignatureManagementPageViewModel)); + services.AddTransient(typeof(MessageListPageViewModel)); + services.AddTransient(typeof(ReadingPanePageViewModel)); + services.AddTransient(typeof(MergedAccountDetailsPageViewModel)); + services.AddTransient(typeof(LanguageTimePageViewModel)); + } + + #endregion + + private IEnumerable GetActivationHandlers() + { + yield return Services.GetService(); + yield return Services.GetService(); + yield return Services.GetService(); + yield return Services.GetService(); + } + } +} diff --git a/Wino.Mail.WinUI/Properties/launchSettings.json b/Wino.Mail.WinUI/Properties/launchSettings.json deleted file mode 100644 index 8d2cf66c..00000000 --- a/Wino.Mail.WinUI/Properties/launchSettings.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "profiles": { - "Wino.Mail.WinUI (Package)": { - "commandName": "MsixPackage" - }, - "Wino.Mail.WinUI (Unpackaged)": { - "commandName": "Project" - } - } -} \ No newline at end of file diff --git a/Wino.Mail.WinUI/Selectors/AccountProviderViewModelTemplateSelector.cs b/Wino.Mail.WinUI/Selectors/AccountProviderViewModelTemplateSelector.cs new file mode 100644 index 00000000..f1a242fa --- /dev/null +++ b/Wino.Mail.WinUI/Selectors/AccountProviderViewModelTemplateSelector.cs @@ -0,0 +1,27 @@ + +using Wino.Mail.ViewModels.Data; + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +#endif + +namespace Wino.Selectors +{ + public class AccountProviderViewModelTemplateSelector : DataTemplateSelector + { + public DataTemplate RootAccountTemplate { get; set; } + public DataTemplate MergedAccountTemplate { get; set; } + + protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) + { + if (item is MergedAccountProviderDetailViewModel) + return MergedAccountTemplate; + else + return RootAccountTemplate; + } + } +} diff --git a/Wino.Mail.WinUI/Selectors/AccountReorderTemplateSelector.cs b/Wino.Mail.WinUI/Selectors/AccountReorderTemplateSelector.cs new file mode 100644 index 00000000..53dd3d6a --- /dev/null +++ b/Wino.Mail.WinUI/Selectors/AccountReorderTemplateSelector.cs @@ -0,0 +1,29 @@ + +using Wino.Mail.ViewModels.Data; + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +#endif + +namespace Wino.Selectors +{ + public class AccountReorderTemplateSelector : DataTemplateSelector + { + public DataTemplate MergedAccountReorderTemplate { get; set; } + public DataTemplate RootAccountReorderTemplate { get; set; } + + protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) + { + if (item is MergedAccountProviderDetailViewModel) + { + return MergedAccountReorderTemplate; + } + + return RootAccountReorderTemplate; + } + } +} diff --git a/Wino.Mail.WinUI/Selectors/AppThemePreviewTemplateSelector.cs b/Wino.Mail.WinUI/Selectors/AppThemePreviewTemplateSelector.cs new file mode 100644 index 00000000..7d27b96d --- /dev/null +++ b/Wino.Mail.WinUI/Selectors/AppThemePreviewTemplateSelector.cs @@ -0,0 +1,32 @@ + +using Wino.Core.UWP.Models.Personalization; + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +#endif + +namespace Wino.Selectors +{ + public class AppThemePreviewTemplateSelector : DataTemplateSelector + { + public DataTemplate SystemThemeTemplate { get; set; } + public DataTemplate PreDefinedThemeTemplate { get; set; } + public DataTemplate CustomAppTemplate { get; set; } + + protected override DataTemplate SelectTemplateCore(object item) + { + if (item is SystemAppTheme) + return SystemThemeTemplate; + else if (item is PreDefinedAppTheme) + return PreDefinedThemeTemplate; + else if (item is CustomAppTheme) + return CustomAppTemplate; + + return base.SelectTemplateCore(item); + } + } +} diff --git a/Wino.Mail.WinUI/Selectors/FileAttachmentTypeSelector.cs b/Wino.Mail.WinUI/Selectors/FileAttachmentTypeSelector.cs new file mode 100644 index 00000000..ac5e8441 --- /dev/null +++ b/Wino.Mail.WinUI/Selectors/FileAttachmentTypeSelector.cs @@ -0,0 +1,58 @@ +using Wino.Core.Domain.Enums; + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +#endif + +namespace Wino.Selectors +{ + public class FileAttachmentTypeSelector : DataTemplateSelector + { + public DataTemplate None { get; set; } + public DataTemplate Executable { get; set; } + public DataTemplate Image { get; set; } + public DataTemplate Audio { get; set; } + public DataTemplate Video { get; set; } + public DataTemplate PDF { get; set; } + public DataTemplate HTML { get; set; } + public DataTemplate RarArchive { get; set; } + public DataTemplate Archive { get; set; } + public DataTemplate Other { get; set; } + + protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) + { + if (item == null) + return None; + + var type = (MailAttachmentType)item; + + switch (type) + { + case MailAttachmentType.None: + return None; + case MailAttachmentType.Executable: + return Executable; + case MailAttachmentType.Image: + return Image; + case MailAttachmentType.Audio: + return Audio; + case MailAttachmentType.Video: + return Video; + case MailAttachmentType.PDF: + return PDF; + case MailAttachmentType.HTML: + return HTML; + case MailAttachmentType.RarArchive: + return RarArchive; + case MailAttachmentType.Archive: + return Archive; + default: + return Other; + } + } + } +} diff --git a/Wino.Mail.WinUI/Selectors/MailItemContainerStyleSelector.cs b/Wino.Mail.WinUI/Selectors/MailItemContainerStyleSelector.cs new file mode 100644 index 00000000..131f4895 --- /dev/null +++ b/Wino.Mail.WinUI/Selectors/MailItemContainerStyleSelector.cs @@ -0,0 +1,26 @@ + +using Wino.Mail.ViewModels.Data; + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +#endif + +namespace Wino.Selectors +{ + public class MailItemContainerStyleSelector : StyleSelector + { + public Style Thread { get; set; } + + protected override Style SelectStyleCore(object item, DependencyObject container) + { + if (item is ThreadMailItemViewModel) + return Thread; + else + return base.SelectStyleCore(item, container); + } + } +} diff --git a/Wino.Mail.WinUI/Selectors/MailItemDisplayModePreviewTemplateSelector.cs b/Wino.Mail.WinUI/Selectors/MailItemDisplayModePreviewTemplateSelector.cs new file mode 100644 index 00000000..0d2692ac --- /dev/null +++ b/Wino.Mail.WinUI/Selectors/MailItemDisplayModePreviewTemplateSelector.cs @@ -0,0 +1,41 @@ + +using Wino.Core.Domain.Enums; + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +#endif + +namespace Wino.Selectors +{ + /// + /// Template selector for previewing mail item display modes in Settings->Personalization page. + /// + public class MailItemDisplayModePreviewTemplateSelector : DataTemplateSelector + { + public DataTemplate CompactTemplate { get; set; } + public DataTemplate MediumTemplate { get; set; } + public DataTemplate SpaciousTemplate { get; set; } + + protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) + { + if (item is MailListDisplayMode mode) + { + switch (mode) + { + case MailListDisplayMode.Spacious: + return SpaciousTemplate; + case MailListDisplayMode.Medium: + return MediumTemplate; + case MailListDisplayMode.Compact: + return CompactTemplate; + } + } + + return base.SelectTemplateCore(item, container); + } + } +} diff --git a/Wino.Mail.WinUI/Selectors/MailItemDisplaySelector.cs b/Wino.Mail.WinUI/Selectors/MailItemDisplaySelector.cs new file mode 100644 index 00000000..cca31237 --- /dev/null +++ b/Wino.Mail.WinUI/Selectors/MailItemDisplaySelector.cs @@ -0,0 +1,28 @@ +using Wino.Mail.ViewModels.Data; + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +#endif + +namespace Wino.Selectors +{ + public class MailItemDisplaySelector : DataTemplateSelector + { + public DataTemplate SingleMailItemTemplate { get; set; } + public DataTemplate ThreadMailItemTemplate { get; set; } + + protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) + { + if (item is MailItemViewModel) + return SingleMailItemTemplate; + else if (item is ThreadMailItemViewModel) + return ThreadMailItemTemplate; + + return base.SelectTemplateCore(item, container); + } + } +} diff --git a/Wino.Mail.WinUI/Selectors/NavigationMenuTemplateSelector.cs b/Wino.Mail.WinUI/Selectors/NavigationMenuTemplateSelector.cs new file mode 100644 index 00000000..5e3518f6 --- /dev/null +++ b/Wino.Mail.WinUI/Selectors/NavigationMenuTemplateSelector.cs @@ -0,0 +1,66 @@ + +using Wino.Core.MenuItems; + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +#endif + +namespace Wino.Selectors +{ + public class NavigationMenuTemplateSelector : DataTemplateSelector + { + public DataTemplate MenuItemTemplate { get; set; } + public DataTemplate AccountManagementTemplate { get; set; } + public DataTemplate ClickableAccountMenuTemplate { get; set; } + public DataTemplate MergedAccountTemplate { get; set; } + public DataTemplate MergedAccountFolderTemplate { get; set; } + public DataTemplate MergedAccountMoreExpansionItemTemplate { get; set; } + public DataTemplate FolderMenuTemplate { get; set; } + public DataTemplate SettingsItemTemplate { get; set; } + public DataTemplate MoreItemsFolderTemplate { get; set; } + public DataTemplate RatingItemTemplate { get; set; } + public DataTemplate CreateNewFolderTemplate { get; set; } + public DataTemplate SeperatorTemplate { get; set; } + public DataTemplate NewMailTemplate { get; set; } + public DataTemplate CategoryItemsTemplate { get; set; } + public DataTemplate FixAuthenticationIssueTemplate { get; set; } + public DataTemplate FixMissingFolderConfigTemplate { get; set; } + + protected override DataTemplate SelectTemplateCore(object item) + { + if (item is NewMailMenuItem) + return NewMailTemplate; + else if (item is SettingsItem) + return SettingsItemTemplate; + else if (item is SeperatorItem) + return SeperatorTemplate; + else if (item is AccountMenuItem accountMenuItem) + // Merged inbox account menu items must be nested. + return ClickableAccountMenuTemplate; + else if (item is ManageAccountsMenuItem) + return AccountManagementTemplate; + else if (item is RateMenuItem) + return RatingItemTemplate; + else if (item is MergedAccountMenuItem) + return MergedAccountTemplate; + else if (item is MergedAccountMoreFolderMenuItem) + return MergedAccountMoreExpansionItemTemplate; + else if (item is MergedAccountFolderMenuItem) + return MergedAccountFolderTemplate; + else if (item is FolderMenuItem) + return FolderMenuTemplate; + else if (item is FixAccountIssuesMenuItem fixAccountIssuesMenuItem) + return fixAccountIssuesMenuItem.Account.AttentionReason == Core.Domain.Enums.AccountAttentionReason.MissingSystemFolderConfiguration + ? FixMissingFolderConfigTemplate : FixAuthenticationIssueTemplate; + else + { + var type = item.GetType(); + return null; + } + } + } +} diff --git a/Wino.Mail.WinUI/Selectors/RendererCommandBarItemTemplateSelector.cs b/Wino.Mail.WinUI/Selectors/RendererCommandBarItemTemplateSelector.cs new file mode 100644 index 00000000..22b55425 --- /dev/null +++ b/Wino.Mail.WinUI/Selectors/RendererCommandBarItemTemplateSelector.cs @@ -0,0 +1,89 @@ +using Wino.Core.Domain.Enums; +using Wino.Core.Domain.Models.Menus; + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +#endif + +namespace Wino.Selectors +{ + public class RendererCommandBarItemTemplateSelector : DataTemplateSelector + { + public DataTemplate Reply { get; set; } + public DataTemplate ReplyAll { get; set; } + public DataTemplate Archive { get; set; } + public DataTemplate Unarchive { get; set; } + public DataTemplate SetFlag { get; set; } + public DataTemplate ClearFlag { get; set; } + public DataTemplate MarkAsRead { get; set; } + public DataTemplate MarkAsUnread { get; set; } + public DataTemplate Delete { get; set; } + public DataTemplate Move { get; set; } + public DataTemplate MoveToJunk { get; set; } + public DataTemplate SaveAs { get; set; } + public DataTemplate Zoom { get; set; } + public DataTemplate Forward { get; set; } + public DataTemplate DarkEditor { get; set; } + public DataTemplate LightEditor { get; set; } + public DataTemplate SeperatorTemplate { get; set; } + public DataTemplate Find { get; set; } + public DataTemplate Print { get; set; } + protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) + { + if (item is MailOperationMenuItem mailOperationItem) + { + switch (mailOperationItem.Operation) + { + case MailOperation.None: + break; + case MailOperation.Archive: + return Archive; + case MailOperation.UnArchive: + return Unarchive; + case MailOperation.SoftDelete: + return Delete; + case MailOperation.Move: + return Move; + case MailOperation.MoveToJunk: + return MoveToJunk; + case MailOperation.SetFlag: + return SetFlag; + case MailOperation.ClearFlag: + return ClearFlag; + case MailOperation.MarkAsRead: + return MarkAsRead; + case MailOperation.MarkAsUnread: + return MarkAsUnread; + case MailOperation.Reply: + return Reply; + case MailOperation.ReplyAll: + return ReplyAll; + case MailOperation.Zoom: + return Zoom; + case MailOperation.SaveAs: + return SaveAs; + case MailOperation.Find: + return Find; + case MailOperation.Forward: + return Forward; + case MailOperation.DarkEditor: + return DarkEditor; + case MailOperation.LightEditor: + return LightEditor; + case MailOperation.Seperator: + return SeperatorTemplate; + case MailOperation.Print: + return Print; + default: + break; + } + } + + return base.SelectTemplateCore(item, container); + } + } +} diff --git a/Wino.Mail.WinUI/Services/ApplicationResourceManager.cs b/Wino.Mail.WinUI/Services/ApplicationResourceManager.cs new file mode 100644 index 00000000..690a0512 --- /dev/null +++ b/Wino.Mail.WinUI/Services/ApplicationResourceManager.cs @@ -0,0 +1,32 @@ +using System.Linq; +using Wino.Core.Domain.Interfaces; +using Wino.Mail.WinUI; + + +#if NET8_0 +using Microsoft.UI.Xaml; +#else +using Windows.UI.Xaml; +#endif +namespace Wino.Services +{ + public class ApplicationResourceManager : IApplicationResourceManager + { + public void AddResource(ResourceDictionary resource) + => App.Current.Resources.MergedDictionaries.Add(resource); + public void RemoveResource(ResourceDictionary resource) + => App.Current.Resources.MergedDictionaries.Remove(resource); + + public bool ContainsResourceKey(string resourceKey) + => App.Current.Resources.ContainsKey(resourceKey); + + public ResourceDictionary GetLastResource() + => App.Current.Resources.MergedDictionaries.LastOrDefault(); + + public void ReplaceResource(string resourceKey, object resource) + => App.Current.Resources[resourceKey] = resource; + + public TReturn GetResource(string resourceKey) + => (TReturn)App.Current.Resources[resourceKey]; + } +} diff --git a/Wino.Mail.WinUI/Services/DialogService.cs b/Wino.Mail.WinUI/Services/DialogService.cs new file mode 100644 index 00000000..e5f81625 --- /dev/null +++ b/Wino.Mail.WinUI/Services/DialogService.cs @@ -0,0 +1,399 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Threading; +using System.Threading.Tasks; +using CommunityToolkit.Mvvm.Messaging; +using Serilog; +using Windows.Storage; +using Windows.Storage.Pickers; +using Wino.Core.Domain; +using Wino.Core.Domain.Entities; +using Wino.Core.Domain.Enums; +using Wino.Core.Domain.Interfaces; +using Wino.Core.Domain.Models.Accounts; +using Wino.Core.Domain.Models.Folders; +using Wino.Core.Domain.Models.Synchronization; +using Wino.Core.Messages.Shell; +using Wino.Core.Messages.Synchronization; +using Wino.Core.UWP.Extensions; +using Wino.Dialogs; +using Wino.Helpers; +using Wino.Core.WinUI.Services; +using Wino.Messaging.Server; +using Windows.Foundation.Metadata; + + + +#if NET8_0 +using Microsoft.UI.Xaml.Controls; +#else +using Windows.UI.Xaml.Controls; +#endif + +namespace Wino.Services +{ + public class DialogService : IDialogService + { + private SemaphoreSlim _presentationSemaphore = new SemaphoreSlim(1); + + private readonly IThemeService _themeService; + private readonly IAppShellService _appShellService; + + public DialogService(IThemeService themeService, IAppShellService appShellService) + { + _themeService = themeService; + _appShellService = appShellService; + } + + public void ShowNotSupportedMessage() + { + InfoBarMessage(Translator.Info_UnsupportedFunctionalityTitle, Translator.Info_UnsupportedFunctionalityDescription, InfoBarMessageType.Error); + } + + public async Task ShowMessageAsync(string message, string title) + { + var dialog = new WinoMessageDialog() + { + RequestedTheme = _themeService.RootTheme.ToWindowsElementTheme() + }; + + AssignXamlRoot(dialog); + + await HandleDialogPresentation(() => dialog.ShowDialogAsync(title, message)); + } + + private void AssignXamlRoot(ContentDialog dialog) + { +#if NET8_0 + if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8)) + { + dialog.XamlRoot = (_appShellService.AppWindow.Content).XamlRoot; + } +#endif + } + + /// + /// Waits for PopupRoot to be available before presenting the dialog and returns the result after presentation. + /// + /// Dialog to present and wait for closing. + /// Dialog result from WinRT. + private async Task HandleDialogPresentationAsync(ContentDialog dialog) + { + await _presentationSemaphore.WaitAsync(); + + try + { + AssignXamlRoot(dialog); + + return await dialog.ShowAsync(); + } + catch (Exception ex) + { + Log.Error(ex, $"Handling dialog service failed. Dialog was {dialog.GetType().Name}"); + } + finally + { + _presentationSemaphore.Release(); + } + + return ContentDialogResult.None; + } + + /// + /// Waits for PopupRoot to be available before executing the given Task that returns customized result. + /// + /// Task that presents the dialog and returns result. + /// Dialog result from the custom dialog. + private async Task HandleDialogPresentation(Func> executionTask) + { + await _presentationSemaphore.WaitAsync(); + + try + { + return await executionTask(); + } + catch (Exception ex) + { + Log.Error(ex, "Handling dialog service failed."); + } + finally + { + _presentationSemaphore.Release(); + } + + return false; + } + + public async Task ShowConfirmationDialogAsync(string question, string title, string confirmationButtonTitle) + { + var dialog = new ConfirmationDialog() + { + RequestedTheme = _themeService.RootTheme.ToWindowsElementTheme() + }; + + AssignXamlRoot(dialog); + + return await HandleDialogPresentation(() => dialog.ShowDialogAsync(title, question, confirmationButtonTitle)); + } + + public async Task ShowNewAccountMailProviderDialogAsync(List availableProviders) + { + var dialog = new NewAccountDialog + { + Providers = availableProviders, + RequestedTheme = _themeService.RootTheme.ToWindowsElementTheme() + }; + + await HandleDialogPresentationAsync(dialog); + + return dialog.Result; + } + + public IAccountCreationDialog GetAccountCreationDialog(MailProviderType type) + { + IAccountCreationDialog dialog = null; + + if (type == MailProviderType.IMAP4) + { + dialog = new NewImapSetupDialog + { + RequestedTheme = _themeService.RootTheme.ToWindowsElementTheme() + }; + } + else + { + dialog = new AccountCreationDialog + { + RequestedTheme = _themeService.RootTheme.ToWindowsElementTheme() + }; + } + + AssignXamlRoot(dialog as ContentDialog); + + return dialog; + } + + public void InfoBarMessage(string title, string message, InfoBarMessageType messageType) + => WeakReferenceMessenger.Default.Send(new InfoBarMessageRequested(messageType, title, message)); + + public void InfoBarMessage(string title, string message, InfoBarMessageType messageType, string actionButtonText, Action action) + => WeakReferenceMessenger.Default.Send(new InfoBarMessageRequested(messageType, title, message, actionButtonText, action)); + + public async Task ShowTextInputDialogAsync(string currentInput, string dialogTitle, string dialogDescription, string primaryButtonText) + { + var inputDialog = new TextInputDialog() + { + CurrentInput = currentInput, + RequestedTheme = _themeService.RootTheme.ToWindowsElementTheme(), + Title = dialogTitle + }; + + inputDialog.SetDescription(dialogDescription); + inputDialog.SetPrimaryButtonText(primaryButtonText); + + await HandleDialogPresentationAsync(inputDialog); + + if (inputDialog.HasInput.GetValueOrDefault() && !currentInput.Equals(inputDialog.CurrentInput)) + return inputDialog.CurrentInput; + + return string.Empty; + } + + public async Task PickWindowsFolderAsync() + { + var picker = new FolderPicker + { + SuggestedStartLocation = PickerLocationId.DocumentsLibrary + }; + + picker.FileTypeFilter.Add("*"); + + var pickedFolder = await picker.PickSingleFolderAsync(); + + if (pickedFolder != null) + { + Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.AddOrReplace("FolderPickerToken", pickedFolder); + + return pickedFolder.Path; + } + + return string.Empty; + } + + public async Task ShowEditAccountDialogAsync(MailAccount account) + { + var editAccountDialog = new AccountEditDialog(account) + { + RequestedTheme = _themeService.RootTheme.ToWindowsElementTheme() + }; + + await HandleDialogPresentationAsync(editAccountDialog); + + return editAccountDialog.IsSaved ? editAccountDialog.Account : null; + } + + public async Task ShowRatingDialogAsync() + { + var storeDialog = new StoreRatingDialog() + { + RequestedTheme = _themeService.RootTheme.ToWindowsElementTheme() + }; + + await HandleDialogPresentationAsync(storeDialog); + + return storeDialog; + } + + public async Task HandleSystemFolderConfigurationDialogAsync(Guid accountId, IFolderService folderService) + { + try + { + var configurableFolder = await folderService.GetFoldersAsync(accountId); + + var systemFolderConfigurationDialog = new SystemFolderConfigurationDialog(configurableFolder) + { + RequestedTheme = _themeService.RootTheme.ToWindowsElementTheme() + }; + + await HandleDialogPresentationAsync(systemFolderConfigurationDialog); + + var configuration = systemFolderConfigurationDialog.Configuration; + + if (configuration != null) + { + var updatedAccount = await folderService.UpdateSystemFolderConfigurationAsync(accountId, configuration); + + // Update account menu item and force re-synchronization. + WeakReferenceMessenger.Default.Send(new AccountUpdatedMessage(updatedAccount)); + + var options = new SynchronizationOptions() + { + AccountId = updatedAccount.Id, + Type = SynchronizationType.Full, + }; + + WeakReferenceMessenger.Default.Send(new NewSynchronizationRequested(options)); + } + + if (configuration != null) + { + InfoBarMessage(Translator.SystemFolderConfigSetupSuccess_Title, Translator.SystemFolderConfigSetupSuccess_Message, InfoBarMessageType.Success); + } + } + catch (Exception ex) + { + InfoBarMessage(Translator.Error_FailedToSetupSystemFolders_Title, ex.Message, InfoBarMessageType.Error); + } + } + + public async Task ShowMoveMailFolderDialogAsync(List availableFolders) + { + var moveDialog = new MoveMailDialog(availableFolders) + { + RequestedTheme = _themeService.RootTheme.ToWindowsElementTheme() + }; + + await HandleDialogPresentationAsync(moveDialog); + + return moveDialog.SelectedFolder; + } + + public async Task PickFolderAsync(Guid accountId, PickFolderReason reason, IFolderService folderService) + { + var allFolders = await folderService.GetFolderStructureForAccountAsync(accountId, true); + + return await ShowMoveMailFolderDialogAsync(allFolders.Folders); + } + + public async Task ShowCustomThemeBuilderDialogAsync() + { + var themeBuilderDialog = new CustomThemeBuilderDialog() + { + RequestedTheme = _themeService.RootTheme.ToWindowsElementTheme() + }; + + var dialogResult = await HandleDialogPresentationAsync(themeBuilderDialog); + + return dialogResult == ContentDialogResult.Primary; + } + + private async Task PickFileAsync(params object[] typeFilters) + { + var picker = new FileOpenPicker + { + ViewMode = PickerViewMode.Thumbnail + }; + + foreach (var filter in typeFilters) + { + picker.FileTypeFilter.Add(filter.ToString()); + } + + var file = await picker.PickSingleFileAsync(); + + if (file == null) return null; + + Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.AddOrReplace("FilePickerPath", file); + + return file; + } + + public async Task PickWindowsFileContentAsync(params object[] typeFilters) + { + var file = await PickFileAsync(typeFilters); + + if (file == null) return Array.Empty(); + + return await file.ReadBytesAsync(); + } + + public Task ShowHardDeleteConfirmationAsync() => ShowConfirmationDialogAsync(Translator.DialogMessage_HardDeleteConfirmationMessage, Translator.DialogMessage_HardDeleteConfirmationTitle, Translator.Buttons_Yes); + + public async Task ShowAccountPickerDialogAsync(List availableAccounts) + { + var accountPicker = new AccountPickerDialog(availableAccounts) + { + RequestedTheme = _themeService.RootTheme.ToWindowsElementTheme() + }; + + await HandleDialogPresentationAsync(accountPicker); + + return accountPicker.PickedAccount; + } + + public async Task ShowSignatureEditorDialog(AccountSignature signatureModel = null) + { + SignatureEditorDialog signatureEditorDialog; + + if (signatureModel != null) + { + signatureEditorDialog = new SignatureEditorDialog(signatureModel) + { + RequestedTheme = _themeService.RootTheme.ToWindowsElementTheme() + }; + } + else + { + signatureEditorDialog = new SignatureEditorDialog() + { + RequestedTheme = _themeService.RootTheme.ToWindowsElementTheme() + }; + } + + var result = await HandleDialogPresentationAsync(signatureEditorDialog); + + return result == ContentDialogResult.Primary ? signatureEditorDialog.Result : null; + } + + public async Task ShowAccountReorderDialogAsync(ObservableCollection availableAccounts) + { + var accountReorderDialog = new AccountReorderDialog(availableAccounts) + { + RequestedTheme = _themeService.RootTheme.ToWindowsElementTheme() + }; + + await HandleDialogPresentationAsync(accountReorderDialog); + } + } +} diff --git a/Wino.Mail.WinUI/Services/LaunchProtocolService.cs b/Wino.Mail.WinUI/Services/LaunchProtocolService.cs new file mode 100644 index 00000000..ff22b45f --- /dev/null +++ b/Wino.Mail.WinUI/Services/LaunchProtocolService.cs @@ -0,0 +1,11 @@ +using System.Collections.Specialized; +using Wino.Core.Domain.Interfaces; + +namespace Wino.Services +{ + public class LaunchProtocolService : ILaunchProtocolService + { + public object LaunchParameter { get; set; } + public NameValueCollection MailtoParameters { get; set; } + } +} diff --git a/Wino.Mail.WinUI/Services/ToastActivationService.cs b/Wino.Mail.WinUI/Services/ToastActivationService.cs new file mode 100644 index 00000000..57eaaf05 --- /dev/null +++ b/Wino.Mail.WinUI/Services/ToastActivationService.cs @@ -0,0 +1,20 @@ +using Wino.Core.Domain.Interfaces; + +namespace Wino.Services +{ + public class ToastActivationService + { + private readonly IMailService _mailService; + private readonly IWinoRequestDelegator _winoRequestDelegator; + private readonly INativeAppService _nativeAppService; + + public ToastActivationService(IMailService mailService, + IWinoRequestDelegator winoRequestDelegator, + INativeAppService nativeAppService) + { + _mailService = mailService; + _winoRequestDelegator = winoRequestDelegator; + _nativeAppService = nativeAppService; + } + } +} diff --git a/Wino.Mail.WinUI/Services/WinoNavigationService.cs b/Wino.Mail.WinUI/Services/WinoNavigationService.cs new file mode 100644 index 00000000..3c3d69f0 --- /dev/null +++ b/Wino.Mail.WinUI/Services/WinoNavigationService.cs @@ -0,0 +1,198 @@ +using System; +using System.Linq; +using CommunityToolkit.Mvvm.Messaging; +using Wino.Core.Domain.Enums; +using Wino.Core.Domain.Interfaces; +using Wino.Core.Domain.Models.MailItem; +using Wino.Core.Domain.Models.Navigation; +using Wino.Helpers; +using Wino.Mail.ViewModels.Data; +using Wino.Mail.ViewModels.Messages; +using Wino.Views; +using Wino.Views.Account; +using Wino.Views.Settings; +using Wino.Core.WinUI.Services; + + +#if NET8_0 +using Microsoft.UI.Xaml.Controls; +using Microsoft.UI.Xaml.Media.Animation; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Media.Animation; +#endif + +namespace Wino.Services +{ + public class WinoNavigationService : IWinoNavigationService + { + private readonly IStatePersistanceService _statePersistanceService; + private readonly IAppShellService _appShellService; + + private WinoPage[] _renderingPageTypes = new WinoPage[] + { + WinoPage.MailRenderingPage, + WinoPage.ComposePage + }; + + + private Frame GetCoreFrame(NavigationReferenceFrame frameType) + { + if (_appShellService.AppWindow.Content is Frame appFrame && appFrame.Content is AppShell shellPage) + return WinoVisualTreeHelper.GetChildObject(shellPage, frameType.ToString()); + + return null; + } + + private Type GetCurrentFrameType(ref Frame _frame) + { + if (_frame != null && _frame.Content != null) + return _frame.Content.GetType(); + else + { + return null; + } + } + + public WinoNavigationService(IStatePersistanceService statePersistanceService, IAppShellService appShellService) + { + _statePersistanceService = statePersistanceService; + _appShellService = appShellService; + } + + private Type GetPageType(WinoPage winoPage) + { + switch (winoPage) + { + case WinoPage.None: + return null; + case WinoPage.IdlePage: + return typeof(IdlePage); + case WinoPage.AccountDetailsPage: + return typeof(AccountDetailsPage); + case WinoPage.MergedAccountDetailsPage: + return typeof(MergedAccountDetailsPage); + case WinoPage.AccountManagementPage: + return typeof(NewAccountManagementPage); + case WinoPage.SignatureManagementPage: + return typeof(SignatureManagementPage); + case WinoPage.AboutPage: + return typeof(AboutPage); + case WinoPage.PersonalizationPage: + return typeof(PersonalizationPage); + case WinoPage.MessageListPage: + return typeof(MessageListPage); + case WinoPage.ReadingPanePage: + return typeof(ReadingPanePage); + case WinoPage.MailRenderingPage: + return typeof(MailRenderingPage); + case WinoPage.ComposePage: + return typeof(ComposePage); + case WinoPage.MailListPage: + return typeof(MailListPage); + case WinoPage.SettingsPage: + return typeof(SettingsPage); + case WinoPage.WelcomePage: + return typeof(WelcomePage); + case WinoPage.SettingOptionsPage: + return typeof(SettingOptionsPage); + default: + return null; + } + } + + public bool Navigate(WinoPage page, + object parameter = null, + NavigationReferenceFrame frame = NavigationReferenceFrame.ShellFrame, + NavigationTransitionType transition = NavigationTransitionType.None) + { + var pageType = GetPageType(page); + Frame shellFrame = GetCoreFrame(NavigationReferenceFrame.ShellFrame); + + _statePersistanceService.IsReadingMail = _renderingPageTypes.Contains(page); + + if (shellFrame != null) + { + var currentFrameType = GetCurrentFrameType(ref shellFrame); + + bool isMailListingPageActive = currentFrameType != null && currentFrameType == typeof(MailListPage); + + // Active page is mail list page and we are refreshing the folder. + if (isMailListingPageActive && currentFrameType == pageType && parameter is NavigateMailFolderEventArgs folderNavigationArgs) + { + // No need for new navigation, just refresh the folder. + WeakReferenceMessenger.Default.Send(new ActiveMailFolderChangedEvent(folderNavigationArgs.BaseFolderMenuItem, folderNavigationArgs.FolderInitLoadAwaitTask)); + + return true; + } + + var transitionInfo = GetNavigationTransitionInfo(transition); + + // This page must be opened in the Frame placed in MailListingPage. + if (isMailListingPageActive && frame == NavigationReferenceFrame.RenderingFrame) + { + var listingFrame = GetCoreFrame(NavigationReferenceFrame.RenderingFrame); + + if (listingFrame == null) return false; + + // Active page is mail list page and we are opening a mail item. + // No navigation needed, just refresh the rendered mail item. + if (listingFrame.Content != null + && listingFrame.Content.GetType() == GetPageType(WinoPage.MailRenderingPage) + && parameter is MailItemViewModel mailItemViewModel + && page != WinoPage.ComposePage) + { + WeakReferenceMessenger.Default.Send(new NewMailItemRenderingRequestedEvent(mailItemViewModel)); + } + else + { + listingFrame.Navigate(pageType, parameter, transitionInfo); + } + + return true; + } + + if ((currentFrameType != null && currentFrameType != pageType) || currentFrameType == null) + { + return shellFrame.Navigate(pageType, parameter, transitionInfo); + } + } + + return false; + } + + private NavigationTransitionInfo GetNavigationTransitionInfo(NavigationTransitionType transition) + { + return transition switch + { + NavigationTransitionType.DrillIn => new DrillInNavigationTransitionInfo(), + _ => new SuppressNavigationTransitionInfo(), + }; + } + + public void NavigateCompose(IMailItem mailItem, NavigationTransitionType transition = NavigationTransitionType.None) + => Navigate(WinoPage.ComposePage, mailItem, NavigationReferenceFrame.RenderingFrame, transition); + + // Standalone EML viewer. + public void NavigateRendering(MimeMessageInformation mimeMessageInformation, NavigationTransitionType transition = NavigationTransitionType.None) + { + if (mimeMessageInformation == null) + throw new ArgumentException("MimeMessage cannot be null."); + + Navigate(WinoPage.MailRenderingPage, mimeMessageInformation, NavigationReferenceFrame.RenderingFrame, transition); + } + + // Mail item view model clicked handler. + public void NavigateRendering(IMailItem mailItem, NavigationTransitionType transition = NavigationTransitionType.None) + { + if (mailItem is MailItemViewModel mailItemViewModel) + Navigate(WinoPage.MailRenderingPage, mailItemViewModel, NavigationReferenceFrame.RenderingFrame, transition); + else + throw new ArgumentException("MailItem must be of type MailItemViewModel."); + } + + public void NavigateFolder(NavigateMailFolderEventArgs args) + => Navigate(WinoPage.MailListPage, args, NavigationReferenceFrame.ShellFrame); + } +} diff --git a/Wino.Mail.WinUI/Styles/Colors.xaml b/Wino.Mail.WinUI/Styles/Colors.xaml new file mode 100644 index 00000000..0da0285c --- /dev/null +++ b/Wino.Mail.WinUI/Styles/Colors.xaml @@ -0,0 +1,24 @@ + + + #e74c3c + #e74c3c + #ff7675 + + #1abc9c + + + + #fdcb6e + #636e72 + + + + #fdcb6e + #2d3436 + + + + diff --git a/Wino.Mail.WinUI/Styles/CommandBarItems.xaml b/Wino.Mail.WinUI/Styles/CommandBarItems.xaml new file mode 100644 index 00000000..dd596d20 --- /dev/null +++ b/Wino.Mail.WinUI/Styles/CommandBarItems.xaml @@ -0,0 +1,158 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wino.Mail.WinUI/Styles/CommandBarItems.xaml.cs b/Wino.Mail.WinUI/Styles/CommandBarItems.xaml.cs new file mode 100644 index 00000000..dbb67bc1 --- /dev/null +++ b/Wino.Mail.WinUI/Styles/CommandBarItems.xaml.cs @@ -0,0 +1,16 @@ +#if NET8_0 +using Microsoft.UI.Xaml; +#else +using Windows.UI.Xaml; +#endif + +namespace Wino.Styles +{ + public partial class CommandBarItems : ResourceDictionary + { + public CommandBarItems() + { + InitializeComponent(); + } + } +} diff --git a/Wino.Mail.WinUI/Styles/ContentPresenters.xaml b/Wino.Mail.WinUI/Styles/ContentPresenters.xaml new file mode 100644 index 00000000..7e1293aa --- /dev/null +++ b/Wino.Mail.WinUI/Styles/ContentPresenters.xaml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + diff --git a/Wino.Mail.WinUI/Styles/Converters.xaml b/Wino.Mail.WinUI/Styles/Converters.xaml new file mode 100644 index 00000000..0ef5e1cb --- /dev/null +++ b/Wino.Mail.WinUI/Styles/Converters.xaml @@ -0,0 +1,7 @@ + + + + diff --git a/Wino.Mail.WinUI/Styles/FontIcons.xaml b/Wino.Mail.WinUI/Styles/FontIcons.xaml new file mode 100644 index 00000000..37409b5d --- /dev/null +++ b/Wino.Mail.WinUI/Styles/FontIcons.xaml @@ -0,0 +1,33 @@ + + + + M128.5,799.5C128.5,778.5 132.5,758.25 140.5,738.75C148.5,719.25 160,702 175,687L525,337C531.333,330.667 538.833,327.5 547.5,327.5C556.167,327.5 563.667,330.667 570,337C576.333,343.333 579.5,350.833 579.5,359.5C579.5,368.167 576.333,375.667 570,382L220,732C211.333,740.667 204.5,750.917 199.5,762.75C194.5,774.583 192,786.833 192,799.5C192,812.833 194.5,825.333 199.5,837C204.5,848.667 211.333,858.833 220,867.5C228.667,876.167 238.833,883 250.5,888C262.167,893 274.667,895.5 288,895.5C300.667,895.5 312.833,893.167 324.5,888.5C336.167,883.833 346.5,877 355.5,868L775,456.5C793,438.833 807,418.083 817,394.25C827,370.417 832,346 832,321C832,295.667 827.083,271.333 817.25,248C807.417,224.667 794,204.083 777,186.25C760,168.417 740.083,154.25 717.25,143.75C694.417,133.25 670,128 644,128C617.333,128 592.083,132.583 568.25,141.75C544.417,150.917 523,165 504,184L120,568C113.667,574.333 106.167,577.5 97.5,577.5C88.8333,577.5 81.3333,574.333 75,568C68.6667,561.667 65.5,554.167 65.5,545.5C65.5,536.833 68.6667,529.333 75,523L459,139C472.333,125.667 485.75,114.25 499.25,104.75C512.75,95.25 526.917,87.5 541.75,81.5C556.583,75.5 572.083,71.0834 588.25,68.25C604.417,65.4167 621.833,64.0001 640.5,64C675.833,64.0001 709,70.8334 740,84.5C771,98.1667 798.083,116.667 821.25,140C844.417,163.333 862.667,190.583 876,221.75C889.333,252.917 896,286.167 896,321.5C896,338.167 894.25,354.75 890.75,371.25C887.25,387.75 882.25,403.833 875.75,419.5C869.25,435.167 861.25,450.083 851.75,464.25C842.25,478.417 831.667,491.167 820,502.5L400.5,914C385.167,929 367.75,940.333 348.25,948C328.75,955.667 308.333,959.5 287,959.5C265,959.5 244.333,955.25 225,946.75C205.667,938.25 188.917,926.75 174.75,912.25C160.583,897.75 149.333,880.833 141,861.5C132.667,842.167 128.5,821.5 128.5,799.5Z + M896,392L896,898.5C896,915.167 892.583,931.083 885.75,946.25C878.917,961.417 869.75,974.75 858.25,986.25C846.75,997.75 833.417,1006.92 818.25,1013.75C803.083,1020.58 787.167,1024 770.5,1024L517,1024C528.667,1014.67 539.833,1004.67 550.5,994C561.167,983.333 571,972 580,960L768,960C777,960 785.333,958.333 793,955C800.667,951.667 807.417,947.083 813.25,941.25C819.083,935.417 823.667,928.667 827,921C830.333,913.333 832,905 832,896L832,392C832,390.667 832,389.333 832,388C832,386.667 831.833,385.333 831.5,384L637.5,384C620.167,384 603.917,380.5 588.75,373.5C573.583,366.5 560.333,357.167 549,345.5C537.667,333.833 528.667,320.25 522,304.75C515.333,289.25 512,273 512,256L512,64.5C510.667,64.1667 509.333,64.0001 508,64C506.667,64.0001 505.333,64.0001 504,64L256,64C247,64.0001 238.667,65.6667 231,69C223.333,72.3334 216.583,76.9167 210.75,82.75C204.917,88.5834 200.333,95.3334 197,103C193.667,110.667 192,119 192,128L192,380.5C169.667,386.5 148.333,394.5 128,404.5L128,125.5C128,108.833 131.417,92.9167 138.25,77.75C145.083,62.5834 154.25,49.2501 165.75,37.75C177.25,26.2501 190.583,17.0834 205.75,10.25C220.917,3.41669 236.833,0 253.5,0L504,0C521,0 537.333,3.25 553,9.75C568.667,16.25 582.5,25.5 594.5,37.5L858.5,301.5C870.5,313.5 879.75,327.333 886.25,343C892.75,358.667 896,375 896,392ZM576,256C576,265 577.667,273.417 581,281.25C584.333,289.083 588.833,295.833 594.5,301.5C600.167,307.167 606.917,311.667 614.75,315C622.583,318.333 631,320 640,320L787,320L576,109ZM576,736C576,775.667 568.417,813 553.25,848C538.083,883 517.5,913.5 491.5,939.5C465.5,965.5 435,986.083 400,1001.25C365,1016.42 327.667,1024 288,1024C248,1024 210.5,1016.5 175.5,1001.5C140.5,986.5 110,966 84,940C58,914 37.5,883.5 22.5,848.5C7.5,813.5 0,776 0,736C0,696.333 7.58333,659 22.75,624C37.9167,589 58.5,558.5 84.5,532.5C110.5,506.5 141,485.917 176,470.75C211,455.583 248.333,448 288,448C314.333,448 339.75,451.417 364.25,458.25C388.75,465.083 411.667,474.75 433,487.25C454.333,499.75 473.833,514.833 491.5,532.5C509.167,550.167 524.25,569.667 536.75,591C549.25,612.333 558.917,635.25 565.75,659.75C572.583,684.25 576,709.667 576,736ZM452,736C452,726 448.5,717.5 441.5,710.5L313.5,582.5C306.5,575.5 298,572 288,572C278,572 269.5,575.5 262.5,582.5L134.5,710.5C127.5,717.5 124,726 124,736C124,746 127.5,754.5 134.5,761.5C141.5,768.5 150,772 160,772C170,772 178.5,768.5 185.5,761.5L256,691L256,864C256,872.667 259.167,880.167 265.5,886.5C271.833,892.833 279.333,896 288,896C296.667,896 304.167,892.833 310.5,886.5C316.833,880.167 320,872.667 320,864L320,691L390.5,761.5C397.5,768.5 406,772 416,772C426,772 434.5,768.5 441.5,761.5C448.5,754.5 452,746 452,736Z + M192,960C174.333,960 157.75,956.667 142.25,950C126.75,943.333 113.167,934.167 101.5,922.5C89.8333,910.833 80.6667,897.25 74,881.75C67.3333,866.25 64,849.667 64,832L64,192C64,174.333 67.3333,157.75 74,142.25C80.6667,126.75 89.8333,113.167 101.5,101.5C113.167,89.8334 126.75,80.6667 142.25,74C157.75,67.3334 174.333,64.0001 192,64L696,64C713,64.0001 729.333,67.2501 745,73.75C760.667,80.2501 774.5,89.5001 786.5,101.5L922.5,237.5C934.5,249.5 943.75,263.333 950.25,279C956.75,294.667 960,311 960,328L960,444C950,436.333 939.667,429.25 929,422.75C918.333,416.25 907.333,410.167 896,404.5L896,328C896,319.333 894.417,311.083 891.25,303.25C888.083,295.417 883.5,288.5 877.5,282.5L741.5,146.5C731.167,136.167 718.667,130.167 704,128.5L704,288C704,301.333 701.5,313.833 696.5,325.5C691.5,337.167 684.667,347.333 676,356C667.333,364.667 657.167,371.5 645.5,376.5C633.833,381.5 621.333,384 608,384L352,384C338.667,384 326.167,381.5 314.5,376.5C302.833,371.5 292.667,364.667 284,356C275.333,347.333 268.5,337.167 263.5,325.5C258.5,313.833 256,301.333 256,288L256,128L192,128C183,128 174.583,129.667 166.75,133C158.917,136.333 152.167,140.833 146.5,146.5C140.833,152.167 136.333,158.917 133,166.75C129.667,174.583 128,183 128,192L128,832C128,841 129.667,849.417 133,857.25C136.333,865.083 140.833,871.833 146.5,877.5C152.167,883.167 158.917,887.667 166.75,891C174.583,894.333 183,896 192,896L192,608C192,594.667 194.5,582.167 199.5,570.5C204.5,558.833 211.333,548.667 220,540C228.667,531.333 238.833,524.5 250.5,519.5C262.167,514.5 274.667,512 288,512L444,512C436.333,522 429.25,532.333 422.75,543C416.25,553.667 410.167,564.667 404.5,576L288,576C279.333,576 271.833,579.167 265.5,585.5C259.167,591.833 256,599.333 256,608L256,896L404.5,896C410.167,907.333 416.25,918.333 422.75,929C429.25,939.667 436.333,950 444,960ZM608,320C616.667,320 624.167,316.833 630.5,310.5C636.833,304.167 640,296.667 640,288L640,128L320,128L320,288C320,296.667 323.167,304.167 329.5,310.5C335.833,316.833 343.333,320 352,320ZM448,736C448,696.333 455.583,659 470.75,624C485.917,589 506.5,558.5 532.5,532.5C558.5,506.5 589,485.917 624,470.75C659,455.583 696.333,448 736,448C762.333,448 787.75,451.417 812.25,458.25C836.75,465.083 859.667,474.75 881,487.25C902.333,499.75 921.833,514.833 939.5,532.5C957.167,550.167 972.25,569.667 984.75,591C997.25,612.333 1006.92,635.25 1013.75,659.75C1020.58,684.25 1024,709.667 1024,736C1024,775.667 1016.42,813 1001.25,848C986.083,883 965.5,913.5 939.5,939.5C913.5,965.5 883,986.083 848,1001.25C813,1016.42 775.667,1024 736,1024C696,1024 658.5,1016.5 623.5,1001.5C588.5,986.5 558,966 532,940C506,914 485.5,883.5 470.5,848.5C455.5,813.5 448,776 448,736ZM736,900C746,900 754.5,896.5 761.5,889.5L889.5,761.5C896.5,754.5 900,746 900,736C900,726 896.5,717.5 889.5,710.5C882.5,703.5 874,700 864,700C854,700 845.5,703.5 838.5,710.5L768,781L768,608C768,599.333 764.833,591.833 758.5,585.5C752.167,579.167 744.667,576 736,576C727.333,576 719.833,579.167 713.5,585.5C707.167,591.833 704,599.333 704,608L704,781L633.5,710.5C626.5,703.5 618,700 608,700C598,700 589.5,703.5 582.5,710.5C575.5,717.5 572,726 572,736C572,746 575.5,754.5 582.5,761.5L710.5,889.5C717.5,896.5 726,900 736,900Z + + + M270.5,954C259.833,954 249.75,952 240.25,948C230.75,944 222.417,938.5 215.25,931.5C208.083,924.5 202.417,916.333 198.25,907C194.083,897.667 192,887.667 192,877L192,147C192,136 194.25,125.5 198.75,115.5C203.25,105.5 209.333,96.6667 217,89C224.667,81.3334 233.5,75.2501 243.5,70.75C253.5,66.2501 264,64.0001 275,64L499,64C534.333,64.0001 567.5,70.7501 598.5,84.25C629.5,97.7501 656.583,116.083 679.75,139.25C702.917,162.417 721.25,189.5 734.75,220.5C748.25,251.5 755,284.667 755,320C755,348.333 750.583,375.25 741.75,400.75C732.917,426.25 720.333,450.5 704,473.5C737.333,499.5 762.75,530.667 780.25,567C797.75,603.333 806.5,642.667 806.5,685C806.5,711.333 803.333,737.083 797,762.25C790.667,787.417 780,811 765,833C752.333,851.667 737.583,868.417 720.75,883.25C703.917,898.083 685.667,910.75 666,921.25C646.333,931.75 625.583,939.75 603.75,945.25C581.917,950.75 559.833,953.5 537.5,953.5C492.833,953.5 448.333,953.583 404,953.75C359.667,953.917 315.167,954 270.5,954ZM493,416C506.333,416 518.833,413.5 530.5,408.5C542.167,403.5 552.333,396.667 561,388C569.667,379.333 576.5,369.167 581.5,357.5C586.5,345.833 589,333.333 589,320C589,306.667 586.5,294.167 581.5,282.5C576.5,270.833 569.667,260.667 561,252C552.333,243.333 542.167,236.5 530.5,231.5C518.833,226.5 506.333,224 493,224L352,224L352,416ZM531,800C546.667,800 561.167,797.083 574.5,791.25C587.833,785.417 599.333,777.5 609,767.5C618.667,757.5 626.25,745.75 631.75,732.25C637.25,718.75 640,704.167 640,688.5C640,673.833 637.083,659.75 631.25,646.25C625.417,632.75 617.583,620.75 607.75,610.25C597.917,599.75 586.417,591.417 573.25,585.25C560.083,579.083 546,576 531,576L352,576L352,800Z + M896,64C904.667,64.0001 912.167,67.1667 918.5,73.5C924.833,79.8334 928,87.3334 928,96C928,104.667 924.833,112.167 918.5,118.5C912.167,124.833 904.667,128 896,128L694,128L398.5,896L608,896C616.667,896 624.167,899.167 630.5,905.5C636.833,911.833 640,919.333 640,928C640,936.667 636.833,944.167 630.5,950.5C624.167,956.833 616.667,960 608,960L128,960C119.333,960 111.833,956.833 105.5,950.5C99.1667,944.167 96,936.667 96,928C96,919.333 99.1667,911.833 105.5,905.5C111.833,899.167 119.333,896 128,896L330,896L625.5,128L416,128C407.333,128 399.833,124.833 393.5,118.5C387.167,112.167 384,104.667 384,96C384,87.3334 387.167,79.8334 393.5,73.5C399.833,67.1667 407.333,64.0001 416,64Z + M192,509L192,96C192,87.3334 195.167,79.8334 201.5,73.5C207.833,67.1667 215.333,64.0001 224,64C232.667,64.0001 240.167,67.1667 246.5,73.5C252.833,79.8334 256,87.3334 256,96L256,514C256,548.667 262.833,581.417 276.5,612.25C290.167,643.083 308.667,670 332,693C355.333,716 382.5,734.25 413.5,747.75C444.5,761.25 477.333,768 512,768C547.667,768 581.083,761.167 612.25,747.5C643.417,733.833 670.5,715.25 693.5,691.75C716.5,668.25 734.667,640.833 748,609.5C761.333,578.167 768,544.667 768,509L768,96C768,87.3334 771.167,79.8334 777.5,73.5C783.833,67.1667 791.333,64.0001 800,64C808.667,64.0001 816.167,67.1667 822.5,73.5C828.833,79.8334 832,87.3334 832,96L832,509C832,538.667 828.25,567.167 820.75,594.5C813.25,621.833 802.583,647.5 788.75,671.5C774.917,695.5 758.25,717.333 738.75,737C719.25,756.667 697.667,773.5 674,787.5C650.333,801.5 624.833,812.417 597.5,820.25C570.167,828.083 541.667,832 512,832C482.333,832 453.833,828.083 426.5,820.25C399.167,812.417 373.667,801.5 350,787.5C326.333,773.5 304.75,756.667 285.25,737C265.75,717.333 249.083,695.5 235.25,671.5C221.417,647.5 210.75,621.75 203.25,594.25C195.75,566.75 192,538.333 192,509ZM224,960C215.333,960 207.833,956.833 201.5,950.5C195.167,944.167 192,936.667 192,928C192,919.333 195.167,911.833 201.5,905.5C207.833,899.167 215.333,896 224,896L800,896C808.667,896 816.167,899.167 822.5,905.5C828.833,911.833 832,919.333 832,928C832,936.667 828.833,944.167 822.5,950.5C816.167,956.833 808.667,960 800,960Z + M270.5,448C218.167,407.333 192,354 192,288C192,271.333 194.667,255.417 200,240.25C205.333,225.083 212.5,210.75 221.5,197.25C230.5,183.75 240.917,171.333 252.75,160C264.583,148.667 277,138.5 290,129.5C322,107.5 357.333,91.0834 396,80.25C434.667,69.4167 473.333,64.0001 512,64C536.333,64.0001 560.5,65.8334 584.5,69.5C608.5,73.1667 632,79.1667 655,87.5C670.333,93.1667 686,99.8334 702,107.5C718,115.167 733.583,124 748.75,134C763.917,144 778.083,154.917 791.25,166.75C804.417,178.583 815.833,191.333 825.5,205C827.833,208.333 829.5,211.25 830.5,213.75C831.5,216.25 832,219.667 832,224C832,232.667 828.833,240.167 822.5,246.5C816.167,252.833 808.667,256 800,256C794,256 789.167,254.917 785.5,252.75C781.833,250.583 778.167,247.333 774.5,243C766.167,233.667 757.833,225 749.5,217C741.167,209 732,201.167 722,193.5C707.333,182.5 691.583,172.833 674.75,164.5C657.917,156.167 640.5,149.333 622.5,144C604.5,138.667 586.167,134.667 567.5,132C548.833,129.333 530.333,128 512,128C479.333,128 446.917,132.333 414.75,141C382.583,149.667 353,163.5 326,182.5C317.667,188.5 309.333,195.25 301,202.75C292.667,210.25 285.167,218.5 278.5,227.5C271.833,236.5 266.417,246.083 262.25,256.25C258.083,266.417 256,277 256,288C256,311.333 260.417,331.5 269.25,348.5C278.083,365.5 289.75,380.25 304.25,392.75C318.75,405.25 335.25,415.917 353.75,424.75C372.25,433.583 391.167,441.333 410.5,448ZM192,800C192,791 195.25,783.417 201.75,777.25C208.25,771.083 215.833,768 224.5,768C230.167,768 235.083,769.25 239.25,771.75C243.417,774.25 247.167,777.667 250.5,782C258.833,792.667 266.333,802.25 273,810.75C279.667,819.25 286.667,827 294,834C301.333,841 309.583,847.417 318.75,853.25C327.917,859.083 339,864.833 352,870.5C376.667,881.167 402.917,888.083 430.75,891.25C458.583,894.417 485.667,896 512,896C528,896 545.417,894.833 564.25,892.5C583.083,890.167 602,886.417 621,881.25C640,876.083 658.333,869.417 676,861.25C693.667,853.083 709.333,843.083 723,831.25C736.667,819.417 747.583,805.583 755.75,789.75C763.917,773.917 768,756 768,736C768,707 761.583,682.833 748.75,663.5C735.917,644.167 717.5,627.167 693.5,612.5C690.5,610.833 685.083,608 677.25,604C669.417,600 661.25,595.917 652.75,591.75C644.25,587.583 636.167,583.917 628.5,580.75C620.833,577.583 615.833,576 613.5,576L96,576C87.3333,576 79.8333,572.833 73.5,566.5C67.1667,560.167 64,552.667 64,544C64,535.333 67.1667,527.833 73.5,521.5C79.8333,515.167 87.3333,512 96,512L928,512C936.667,512 944.167,515.167 950.5,521.5C956.833,527.833 960,535.333 960,544C960,552.667 956.833,560.167 950.5,566.5C944.167,572.833 936.667,576 928,576L753.5,576C805.833,616.667 832,670 832,736C832,763 827.167,787.25 817.5,808.75C807.833,830.25 794.917,849.333 778.75,866C762.583,882.667 743.75,896.917 722.25,908.75C700.75,920.583 678.167,930.333 654.5,938C630.833,945.667 606.75,951.25 582.25,954.75C557.75,958.25 534.333,960 512,960C480.667,960 449.333,958.083 418,954.25C386.667,950.417 356.333,942.167 327,929.5C301,918.167 276.667,902.833 254,883.5C231.333,864.167 212.5,842.333 197.5,818C193.833,812.333 192,806.333 192,800Z + M0,224C0,215 1.66667,206.667 5,199C8.33333,191.333 12.9167,184.583 18.75,178.75C24.5833,172.917 31.3333,168.333 39,165C46.6667,161.667 55,160 64,160C72.6667,160 80.9167,161.667 88.75,165C96.5833,168.333 103.417,172.917 109.25,178.75C115.083,184.583 119.667,191.417 123,199.25C126.333,207.083 128,215.333 128,224C128,233 126.333,241.333 123,249C119.667,256.667 115.083,263.417 109.25,269.25C103.417,275.083 96.6667,279.667 89,283C81.3333,286.333 73,288 64,288C55,288 46.5833,286.333 38.75,283C30.9167,279.667 24.1667,275.167 18.5,269.5C12.8333,263.833 8.33333,257.083 5,249.25C1.66667,241.417 0,233 0,224ZM288,256C279.333,256 271.833,252.833 265.5,246.5C259.167,240.167 256,232.667 256,224C256,215.333 259.167,207.833 265.5,201.5C271.833,195.167 279.333,192 288,192L992,192C1000.67,192 1008.17,195.167 1014.5,201.5C1020.83,207.833 1024,215.333 1024,224C1024,232.667 1020.83,240.167 1014.5,246.5C1008.17,252.833 1000.67,256 992,256ZM0,480C0,471 1.66667,462.667 5,455C8.33333,447.333 12.9167,440.583 18.75,434.75C24.5833,428.917 31.3333,424.333 39,421C46.6667,417.667 55,416 64,416C72.6667,416 80.9167,417.667 88.75,421C96.5833,424.333 103.417,428.917 109.25,434.75C115.083,440.583 119.667,447.417 123,455.25C126.333,463.083 128,471.333 128,480C128,489 126.333,497.333 123,505C119.667,512.667 115.083,519.417 109.25,525.25C103.417,531.083 96.6667,535.667 89,539C81.3333,542.333 73,544 64,544C55,544 46.5833,542.333 38.75,539C30.9167,535.667 24.1667,531.167 18.5,525.5C12.8333,519.833 8.33333,513.083 5,505.25C1.66667,497.417 0,489 0,480ZM288,512C279.333,512 271.833,508.833 265.5,502.5C259.167,496.167 256,488.667 256,480C256,471.333 259.167,463.833 265.5,457.5C271.833,451.167 279.333,448 288,448L992,448C1000.67,448 1008.17,451.167 1014.5,457.5C1020.83,463.833 1024,471.333 1024,480C1024,488.667 1020.83,496.167 1014.5,502.5C1008.17,508.833 1000.67,512 992,512ZM0,736C0,727 1.66667,718.667 5,711C8.33333,703.333 12.9167,696.583 18.75,690.75C24.5833,684.917 31.3333,680.333 39,677C46.6667,673.667 55,672 64,672C72.6667,672 80.9167,673.667 88.75,677C96.5833,680.333 103.417,684.917 109.25,690.75C115.083,696.583 119.667,703.417 123,711.25C126.333,719.083 128,727.333 128,736C128,745 126.333,753.333 123,761C119.667,768.667 115.083,775.417 109.25,781.25C103.417,787.083 96.6667,791.667 89,795C81.3333,798.333 73,800 64,800C55,800 46.5833,798.333 38.75,795C30.9167,791.667 24.1667,787.167 18.5,781.5C12.8333,775.833 8.33333,769.083 5,761.25C1.66667,753.417 0,745 0,736ZM288,768C279.333,768 271.833,764.833 265.5,758.5C259.167,752.167 256,744.667 256,736C256,727.333 259.167,719.833 265.5,713.5C271.833,707.167 279.333,704 288,704L992,704C1000.67,704 1008.17,707.167 1014.5,713.5C1020.83,719.833 1024,727.333 1024,736C1024,744.667 1020.83,752.167 1014.5,758.5C1008.17,764.833 1000.67,768 992,768Z + F1 M 15 6.25 C 14.824218 6.25 14.65983 6.217448 14.506836 6.152344 C 14.353841 6.08724 14.222005 5.99935 14.111328 5.888672 C 14.00065 5.777995 13.91276 5.646159 13.847656 5.493164 C 13.782552 5.34017 13.75 5.175782 13.75 5 L 13.75 2.5 C 13.75 2.324219 13.782552 2.161459 13.847656 2.011719 C 13.91276 1.86198 14.002277 1.730145 14.116211 1.616211 C 14.230143 1.502279 14.361979 1.412762 14.511719 1.347656 C 14.661457 1.282553 14.824218 1.25 15 1.25 L 17.5 1.25 C 17.66927 1.25 17.830402 1.282553 17.983398 1.347656 C 18.136393 1.412762 18.269855 1.502279 18.383789 1.616211 C 18.497721 1.730145 18.587238 1.863607 18.652344 2.016602 C 18.717447 2.169598 18.75 2.33073 18.75 2.5 L 18.75 5 C 18.75 5.175782 18.717447 5.338543 18.652344 5.488281 C 18.587238 5.638021 18.497721 5.769857 18.383789 5.883789 C 18.269855 5.997723 18.13802 6.08724 17.988281 6.152344 C 17.838541 6.217448 17.675781 6.25 17.5 6.25 Z M 1.875 3.75 C 1.705729 3.75 1.559245 3.688152 1.435547 3.564453 C 1.311849 3.440756 1.25 3.294271 1.25 3.125 C 1.25 2.95573 1.311849 2.809246 1.435547 2.685547 C 1.559245 2.56185 1.705729 2.5 1.875 2.5 L 11.875 2.5 C 12.04427 2.5 12.190754 2.56185 12.314453 2.685547 C 12.43815 2.809246 12.5 2.95573 12.5 3.125 C 12.5 3.294271 12.43815 3.440756 12.314453 3.564453 C 12.190754 3.688152 12.04427 3.75 11.875 3.75 Z M 15 2.5 L 15 5 L 17.5 5 L 17.5 2.5 Z M 15 12.5 C 14.824218 12.5 14.65983 12.467448 14.506836 12.402344 C 14.353841 12.33724 14.222005 12.24935 14.111328 12.138672 C 14.00065 12.027995 13.91276 11.896159 13.847656 11.743164 C 13.782552 11.59017 13.75 11.425781 13.75 11.25 L 13.75 8.75 C 13.75 8.574219 13.782552 8.411459 13.847656 8.261719 C 13.91276 8.111979 14.002277 7.980144 14.116211 7.866211 C 14.230143 7.752279 14.361979 7.662762 14.511719 7.597656 C 14.661457 7.532553 14.824218 7.5 15 7.5 L 17.5 7.5 C 17.66927 7.5 17.830402 7.532553 17.983398 7.597656 C 18.136393 7.662762 18.269855 7.752279 18.383789 7.866211 C 18.497721 7.980144 18.587238 8.113607 18.652344 8.266602 C 18.717447 8.419597 18.75 8.580729 18.75 8.75 L 18.75 11.25 C 18.75 11.425781 18.717447 11.588542 18.652344 11.738281 C 18.587238 11.888021 18.497721 12.019857 18.383789 12.133789 C 18.269855 12.247722 18.13802 12.33724 17.988281 12.402344 C 17.838541 12.467448 17.675781 12.5 17.5 12.5 Z M 1.875 10 C 1.705729 10 1.559245 9.938151 1.435547 9.814453 C 1.311849 9.690756 1.25 9.544271 1.25 9.375 C 1.25 9.205729 1.311849 9.059245 1.435547 8.935547 C 1.559245 8.81185 1.705729 8.75 1.875 8.75 L 11.875 8.75 C 12.04427 8.75 12.190754 8.81185 12.314453 8.935547 C 12.43815 9.059245 12.5 9.205729 12.5 9.375 C 12.5 9.544271 12.43815 9.690756 12.314453 9.814453 C 12.190754 9.938151 12.04427 10 11.875 10 Z M 15 8.75 L 15 11.25 L 17.5 11.25 L 17.5 8.75 Z M 15 18.75 C 14.824218 18.75 14.65983 18.717447 14.506836 18.652344 C 14.353841 18.58724 14.222005 18.49935 14.111328 18.388672 C 14.00065 18.277994 13.91276 18.146158 13.847656 17.993164 C 13.782552 17.84017 13.75 17.675781 13.75 17.5 L 13.75 15 C 13.75 14.824219 13.782552 14.661459 13.847656 14.511719 C 13.91276 14.361979 14.002277 14.230144 14.116211 14.116211 C 14.230143 14.002279 14.361979 13.912761 14.511719 13.847656 C 14.661457 13.782553 14.824218 13.75 15 13.75 L 17.5 13.75 C 17.66927 13.75 17.830402 13.782553 17.983398 13.847656 C 18.136393 13.912761 18.269855 14.002279 18.383789 14.116211 C 18.497721 14.230144 18.587238 14.363607 18.652344 14.516602 C 18.717447 14.669597 18.75 14.830729 18.75 15 L 18.75 17.5 C 18.75 17.675781 18.717447 17.838541 18.652344 17.988281 C 18.587238 18.138021 18.497721 18.269857 18.383789 18.383789 C 18.269855 18.497721 18.13802 18.58724 17.988281 18.652344 C 17.838541 18.717447 17.675781 18.75 17.5 18.75 Z M 1.875 16.25 C 1.705729 16.25 1.559245 16.188152 1.435547 16.064453 C 1.311849 15.940756 1.25 15.794271 1.25 15.625 C 1.25 15.455729 1.311849 15.309245 1.435547 15.185547 C 1.559245 15.06185 1.705729 15 1.875 15 L 11.875 15 C 12.04427 15 12.190754 15.06185 12.314453 15.185547 C 12.43815 15.309245 12.5 15.455729 12.5 15.625 C 12.5 15.794271 12.43815 15.940756 12.314453 16.064453 C 12.190754 16.188152 12.04427 16.25 11.875 16.25 Z M 15 15 L 15 17.5 L 17.5 17.5 L 17.5 15 Z + M288,192C279.333,192 271.833,188.833 265.5,182.5C259.167,176.167 256,168.667 256,160C256,151.333 259.167,143.833 265.5,137.5C271.833,131.167 279.333,128 288,128L800,128C808.667,128 816.167,131.167 822.5,137.5C828.833,143.833 832,151.333 832,160C832,168.667 828.833,176.167 822.5,182.5C816.167,188.833 808.667,192 800,192ZM0,480C0,471.333 3.16667,463.833 9.5,457.5L100,367C106.333,360.667 113.833,357.5 122.5,357.5C131.167,357.5 138.667,360.667 145,367C151.333,373.333 154.5,380.833 154.5,389.5C154.5,398.167 151.333,405.667 145,412L77.5,480L145,548C151.333,554.333 154.5,561.833 154.5,570.5C154.5,579.167 151.333,586.667 145,593C138.667,599.333 131.167,602.5 122.5,602.5C113.833,602.5 106.333,599.333 100,593L9.5,502.5C3.16667,496.167 0,488.667 0,480ZM288,512C279.333,512 271.833,508.833 265.5,502.5C259.167,496.167 256,488.667 256,480C256,471.333 259.167,463.833 265.5,457.5C271.833,451.167 279.333,448 288,448L992,448C1000.67,448 1008.17,451.167 1014.5,457.5C1020.83,463.833 1024,471.333 1024,480C1024,488.667 1020.83,496.167 1014.5,502.5C1008.17,508.833 1000.67,512 992,512ZM288,832C279.333,832 271.833,828.833 265.5,822.5C259.167,816.167 256,808.667 256,800C256,791.333 259.167,783.833 265.5,777.5C271.833,771.167 279.333,768 288,768L672,768C680.667,768 688.167,771.167 694.5,777.5C700.833,783.833 704,791.333 704,800C704,808.667 700.833,816.167 694.5,822.5C688.167,828.833 680.667,832 672,832Z + M288,192C279.333,192 271.833,188.833 265.5,182.5C259.167,176.167 256,168.667 256,160C256,151.333 259.167,143.833 265.5,137.5C271.833,131.167 279.333,128 288,128L800,128C808.667,128 816.167,131.167 822.5,137.5C828.833,143.833 832,151.333 832,160C832,168.667 828.833,176.167 822.5,182.5C816.167,188.833 808.667,192 800,192ZM0,570.5C0,561.833 3.16667,554.333 9.5,548L77.5,480L9.5,412C3.16667,405.667 0,398.167 0,389.5C0,380.833 3.16667,373.333 9.5,367C15.8333,360.667 23.3333,357.5 32,357.5C40.6667,357.5 48.1667,360.667 54.5,367L145,457.5C151.333,463.833 154.5,471.333 154.5,480C154.5,488.667 151.333,496.167 145,502.5L54.5,593C48.1667,599.333 40.6667,602.5 32,602.5C23.3333,602.5 15.8333,599.333 9.5,593C3.16667,586.667 0,579.167 0,570.5ZM288,512C279.333,512 271.833,508.833 265.5,502.5C259.167,496.167 256,488.667 256,480C256,471.333 259.167,463.833 265.5,457.5C271.833,451.167 279.333,448 288,448L992,448C1000.67,448 1008.17,451.167 1014.5,457.5C1020.83,463.833 1024,471.333 1024,480C1024,488.667 1020.83,496.167 1014.5,502.5C1008.17,508.833 1000.67,512 992,512ZM288,832C279.333,832 271.833,828.833 265.5,822.5C259.167,816.167 256,808.667 256,800C256,791.333 259.167,783.833 265.5,777.5C271.833,771.167 279.333,768 288,768L672,768C680.667,768 688.167,771.167 694.5,777.5C700.833,783.833 704,791.333 704,800C704,808.667 700.833,816.167 694.5,822.5C688.167,828.833 680.667,832 672,832Z + M768,576L667,576C632.333,576 599.75,569.083 569.25,555.25C538.75,541.417 512.167,522.75 489.5,499.25C466.833,475.75 448.917,448.583 435.75,417.75C422.583,386.917 416,354.333 416,320C416,285.667 422.583,253.083 435.75,222.25C448.917,191.417 466.833,164.25 489.5,140.75C512.167,117.25 538.75,98.5834 569.25,84.75C599.75,70.9167 632.333,64.0001 667,64L992,64C1000.67,64.0001 1008.17,67.1667 1014.5,73.5C1020.83,79.8334 1024,87.3334 1024,96C1024,103.333 1022.58,109.167 1019.75,113.5C1016.92,117.833 1013.25,121.083 1008.75,123.25C1004.25,125.417 999.25,126.833 993.75,127.5C988.25,128.167 982.667,128.5 977,128.5C974,128.5 971.083,128.417 968.25,128.25C965.417,128.083 962.667,128 960,128L960,992C960,1000.67 956.833,1008.17 950.5,1014.5C944.167,1020.83 936.667,1024 928,1024C919.333,1024 911.833,1020.83 905.5,1014.5C899.167,1008.17 896,1000.67 896,992L896,128L832,128L832,992C832,1000.67 828.833,1008.17 822.5,1014.5C816.167,1020.83 808.667,1024 800,1024C791.333,1024 783.833,1020.83 777.5,1014.5C771.167,1008.17 768,1000.67 768,992ZM768,512L768,128L668,128C642,128 617.583,133.167 594.75,143.5C571.917,153.833 552,167.833 535,185.5C518,203.167 504.583,223.583 494.75,246.75C484.917,269.917 480,294.333 480,320C480,345.667 484.917,370.083 494.75,393.25C504.583,416.417 518,436.833 535,454.5C552,472.167 571.917,486.167 594.75,496.5C617.583,506.833 642,512 668,512ZM64,672C64,663.333 67.1667,655.833 73.5,649.5L243,480L73.5,310.5C67.1667,304.167 64,296.667 64,288C64,279.333 67.1667,271.833 73.5,265.5C79.8333,259.167 87.3333,256 96,256C104.667,256 112.167,259.167 118.5,265.5L310.5,457.5C316.833,463.833 320,471.333 320,480C320,488.667 316.833,496.167 310.5,502.5L118.5,694.5C112.167,700.833 104.667,704 96,704C87.3333,704 79.8333,700.833 73.5,694.5C67.1667,688.167 64,680.667 64,672Z + M832,706.5C832,723.167 828.583,739.083 821.75,754.25C814.917,769.417 805.75,782.75 794.25,794.25C782.75,805.75 769.417,814.917 754.25,821.75C739.083,828.583 723.167,832 706.5,832L189.5,832C172.833,832 156.917,828.583 141.75,821.75C126.583,814.917 113.25,805.75 101.75,794.25C90.25,782.75 81.0833,769.417 74.25,754.25C67.4167,739.083 64,723.167 64,706.5L64,189.5C64,172.833 67.4167,156.917 74.25,141.75C81.0833,126.583 90.25,113.25 101.75,101.75C113.25,90.25 126.583,81.0834 141.75,74.25C156.917,67.4167 172.833,64.0001 189.5,64L706.5,64C723.167,64.0001 739.083,67.4167 754.25,74.25C769.417,81.0834 782.75,90.25 794.25,101.75C805.75,113.25 814.917,126.583 821.75,141.75C828.583,156.917 832,172.833 832,189.5ZM128,704C128,706.667 128.167,709.5 128.5,712.5C128.833,715.5 129.333,718.333 130,721L357.5,493C369.167,481.333 383,472.417 399,466.25C415,460.083 431.333,457 448,457C465,457 481.417,460 497.25,466C513.083,472 526.833,481 538.5,493L766,721C766.667,718.333 767.167,715.5 767.5,712.5C767.833,709.5 768,706.667 768,704L768,192C768,183.333 766.333,175.083 763,167.25C759.667,159.417 755.083,152.583 749.25,146.75C743.417,140.917 736.583,136.333 728.75,133C720.917,129.667 712.667,128 704,128L192,128C183,128 174.667,129.667 167,133C159.333,136.333 152.583,140.917 146.75,146.75C140.917,152.583 136.333,159.333 133,167C129.667,174.667 128,183 128,192ZM960,320L960,772C960,797 954.917,820.917 944.75,843.75C934.583,866.583 920.917,886.583 903.75,903.75C886.583,920.917 866.583,934.583 843.75,944.75C820.917,954.917 797,960 772,960L320,960C297,960 275.583,954.333 255.75,943C235.917,931.667 220.333,916 209,896L770.5,896C787.833,896 804.083,892.5 819.25,885.5C834.417,878.5 847.667,869.167 859,857.5C870.333,845.833 879.333,832.25 886,816.75C892.667,801.25 896,785 896,768L896,209C916,220.333 931.667,235.917 943,255.75C954.333,275.583 960,297 960,320ZM544,288C544,279 545.667,270.667 549,263C552.333,255.333 556.917,248.583 562.75,242.75C568.583,236.917 575.333,232.333 583,229C590.667,225.667 599,224 608,224C616.667,224 624.917,225.667 632.75,229C640.583,232.333 647.417,236.917 653.25,242.75C659.083,248.583 663.667,255.417 667,263.25C670.333,271.083 672,279.333 672,288C672,297 670.333,305.333 667,313C663.667,320.667 659.083,327.417 653.25,333.25C647.417,339.083 640.667,343.667 633,347C625.333,350.333 617,352 608,352C599,352 590.583,350.333 582.75,347C574.917,343.667 568.167,339.167 562.5,333.5C556.833,327.833 552.333,321.083 549,313.25C545.667,305.417 544,297 544,288ZM175,766C177.667,766.667 180.5,767.167 183.5,767.5C186.5,767.833 189.333,768 192,768L704,768C706.667,768 709.5,767.833 712.5,767.5C715.5,767.167 718.333,766.667 721,766L493.5,538.5C487.5,532.5 480.5,528 472.5,525C464.5,522 456.333,520.5 448,520.5C439.667,520.5 431.583,522 423.75,525C415.917,528 409,532.5 403,538.5Z + M32,192C23.3333,192 15.8333,188.833 9.5,182.5C3.16667,176.167 0,168.667 0,160C0,151.333 3.16667,143.833 9.5,137.5C15.8333,131.167 23.3333,128 32,128L736,128C744.667,128 752.167,131.167 758.5,137.5C764.833,143.833 768,151.333 768,160C768,168.667 764.833,176.167 758.5,182.5C752.167,188.833 744.667,192 736,192ZM32,512C23.3333,512 15.8333,508.833 9.5,502.5C3.16667,496.167 0,488.667 0,480C0,471.333 3.16667,463.833 9.5,457.5C15.8333,451.167 23.3333,448 32,448L992,448C1000.67,448 1008.17,451.167 1014.5,457.5C1020.83,463.833 1024,471.333 1024,480C1024,488.667 1020.83,496.167 1014.5,502.5C1008.17,508.833 1000.67,512 992,512ZM32,832C23.3333,832 15.8333,828.833 9.5,822.5C3.16667,816.167 0,808.667 0,800C0,791.333 3.16667,783.833 9.5,777.5C15.8333,771.167 23.3333,768 32,768L608,768C616.667,768 624.167,771.167 630.5,777.5C636.833,783.833 640,791.333 640,800C640,808.667 636.833,816.167 630.5,822.5C624.167,828.833 616.667,832 608,832Z + M160,192C151.333,192 143.833,188.833 137.5,182.5C131.167,176.167 128,168.667 128,160C128,151.333 131.167,143.833 137.5,137.5C143.833,131.167 151.333,128 160,128L864,128C872.667,128 880.167,131.167 886.5,137.5C892.833,143.833 896,151.333 896,160C896,168.667 892.833,176.167 886.5,182.5C880.167,188.833 872.667,192 864,192ZM32,512C23.3333,512 15.8333,508.833 9.5,502.5C3.16667,496.167 0,488.667 0,480C0,471.333 3.16667,463.833 9.5,457.5C15.8333,451.167 23.3333,448 32,448L992,448C1000.67,448 1008.17,451.167 1014.5,457.5C1020.83,463.833 1024,471.333 1024,480C1024,488.667 1020.83,496.167 1014.5,502.5C1008.17,508.833 1000.67,512 992,512ZM288,832C279.333,832 271.833,828.833 265.5,822.5C259.167,816.167 256,808.667 256,800C256,791.333 259.167,783.833 265.5,777.5C271.833,771.167 279.333,768 288,768L736,768C744.667,768 752.167,771.167 758.5,777.5C764.833,783.833 768,791.333 768,800C768,808.667 764.833,816.167 758.5,822.5C752.167,828.833 744.667,832 736,832Z + M288,192C279.333,192 271.833,188.833 265.5,182.5C259.167,176.167 256,168.667 256,160C256,151.333 259.167,143.833 265.5,137.5C271.833,131.167 279.333,128 288,128L992,128C1000.67,128 1008.17,131.167 1014.5,137.5C1020.83,143.833 1024,151.333 1024,160C1024,168.667 1020.83,176.167 1014.5,182.5C1008.17,188.833 1000.67,192 992,192ZM32,512C23.3333,512 15.8333,508.833 9.5,502.5C3.16667,496.167 0,488.667 0,480C0,471.333 3.16667,463.833 9.5,457.5C15.8333,451.167 23.3333,448 32,448L992,448C1000.67,448 1008.17,451.167 1014.5,457.5C1020.83,463.833 1024,471.333 1024,480C1024,488.667 1020.83,496.167 1014.5,502.5C1008.17,508.833 1000.67,512 992,512ZM480,832C471.333,832 463.833,828.833 457.5,822.5C451.167,816.167 448,808.667 448,800C448,791.333 451.167,783.833 457.5,777.5C463.833,771.167 471.333,768 480,768L992,768C1000.67,768 1008.17,771.167 1014.5,777.5C1020.83,783.833 1024,791.333 1024,800C1024,808.667 1020.83,816.167 1014.5,822.5C1008.17,828.833 1000.67,832 992,832Z + M32,192C23.3333,192 15.8333,188.833 9.5,182.5C3.16667,176.167 0,168.667 0,160C0,151.333 3.16667,143.833 9.5,137.5C15.8333,131.167 23.3333,128 32,128L992,128C1000.67,128 1008.17,131.167 1014.5,137.5C1020.83,143.833 1024,151.333 1024,160C1024,168.667 1020.83,176.167 1014.5,182.5C1008.17,188.833 1000.67,192 992,192ZM32,512C23.3333,512 15.8333,508.833 9.5,502.5C3.16667,496.167 0,488.667 0,480C0,471.333 3.16667,463.833 9.5,457.5C15.8333,451.167 23.3333,448 32,448L992,448C1000.67,448 1008.17,451.167 1014.5,457.5C1020.83,463.833 1024,471.333 1024,480C1024,488.667 1020.83,496.167 1014.5,502.5C1008.17,508.833 1000.67,512 992,512ZM32,832C23.3333,832 15.8333,828.833 9.5,822.5C3.16667,816.167 0,808.667 0,800C0,791.333 3.16667,783.833 9.5,777.5C15.8333,771.167 23.3333,768 32,768L992,768C1000.67,768 1008.17,771.167 1014.5,777.5C1020.83,783.833 1024,791.333 1024,800C1024,808.667 1020.83,816.167 1014.5,822.5C1008.17,828.833 1000.67,832 992,832Z + F1 M 0 10 C 0 9.082031 0.118815 8.196615 0.356445 7.34375 C 0.594076 6.490886 0.93099 5.694987 1.367188 4.956055 C 1.803385 4.217123 2.325846 3.543295 2.93457 2.93457 C 3.543294 2.325848 4.217122 1.803387 4.956055 1.367188 C 5.694986 0.93099 6.490885 0.594076 7.34375 0.356445 C 8.196614 0.118816 9.082031 0 10 0 C 10.917969 0 11.803385 0.118816 12.65625 0.356445 C 13.509114 0.594076 14.305013 0.93099 15.043945 1.367188 C 15.782877 1.803387 16.456705 2.325848 17.06543 2.93457 C 17.674152 3.543295 18.196613 4.217123 18.632812 4.956055 C 19.06901 5.694987 19.405924 6.490886 19.643555 7.34375 C 19.881184 8.196615 20 9.082031 20 10 C 20 10.917969 19.881184 11.803386 19.643555 12.65625 C 19.405924 13.509115 19.06901 14.305014 18.632812 15.043945 C 18.196613 15.782878 17.674152 16.456705 17.06543 17.06543 C 16.456705 17.674154 15.782877 18.196615 15.043945 18.632812 C 14.305013 19.06901 13.509114 19.405924 12.65625 19.643555 C 11.803385 19.881186 10.917969 20 10 20 C 9.082031 20 8.196614 19.881186 7.34375 19.643555 C 6.490885 19.405924 5.694986 19.06901 4.956055 18.632812 C 4.217122 18.196615 3.543294 17.674154 2.93457 17.06543 C 2.325846 16.456705 1.803385 15.782878 1.367188 15.043945 C 0.93099 14.305014 0.594076 13.509115 0.356445 12.65625 C 0.118815 11.803386 0 10.917969 0 10 Z M 18.75 10 C 18.75 9.199219 18.645832 8.426107 18.4375 7.680664 C 18.229166 6.935222 17.93457 6.238607 17.553711 5.59082 C 17.172852 4.943035 16.715494 4.352215 16.181641 3.818359 C 15.647785 3.284506 15.056965 2.827148 14.40918 2.446289 C 13.761393 2.06543 13.064778 1.770834 12.319336 1.5625 C 11.573893 1.354168 10.800781 1.25 10 1.25 C 9.192708 1.25 8.416341 1.354168 7.670898 1.5625 C 6.925456 1.770834 6.228841 2.06543 5.581055 2.446289 C 4.933268 2.827148 4.344075 3.282879 3.813477 3.813477 C 3.282877 4.344076 2.827148 4.933269 2.446289 5.581055 C 2.06543 6.228842 1.770833 6.925457 1.5625 7.670898 C 1.354167 8.416342 1.25 9.192709 1.25 10 C 1.25 10.807292 1.354167 11.583659 1.5625 12.329102 C 1.770833 13.074545 2.06543 13.771159 2.446289 14.418945 C 2.827148 15.066732 3.282877 15.655925 3.813477 16.186523 C 4.344075 16.717123 4.933268 17.172852 5.581055 17.553711 C 6.228841 17.93457 6.925456 18.229166 7.670898 18.4375 C 8.416341 18.645834 9.192708 18.75 10 18.75 C 10.807291 18.75 11.583658 18.645834 12.329102 18.4375 C 13.074543 18.229166 13.771158 17.93457 14.418945 17.553711 C 15.066731 17.172852 15.655924 16.717123 16.186523 16.186523 C 16.717121 15.655925 17.172852 15.066732 17.553711 14.418945 C 17.93457 13.771159 18.229166 13.074545 18.4375 12.329102 C 18.645832 11.583659 18.75 10.807292 18.75 10 Z M 5.625 8.125 C 5.625 7.949219 5.657552 7.786459 5.722656 7.636719 C 5.78776 7.486979 5.877278 7.355144 5.991211 7.241211 C 6.105143 7.127279 6.236979 7.037761 6.386719 6.972656 C 6.536458 6.907553 6.699219 6.875001 6.875 6.875 C 7.044271 6.875001 7.205403 6.907553 7.358398 6.972656 C 7.511393 7.037761 7.644856 7.127279 7.758789 7.241211 C 7.872721 7.355144 7.962239 7.488607 8.027344 7.641602 C 8.092447 7.794598 8.125 7.95573 8.125 8.125 C 8.125 8.300781 8.092447 8.463542 8.027344 8.613281 C 7.962239 8.763021 7.872721 8.894857 7.758789 9.008789 C 7.644856 9.122722 7.513021 9.21224 7.363281 9.277344 C 7.213542 9.342448 7.050781 9.375 6.875 9.375 C 6.699219 9.375 6.534831 9.342448 6.381836 9.277344 C 6.228841 9.21224 6.097005 9.12435 5.986328 9.013672 C 5.875651 8.902995 5.78776 8.771159 5.722656 8.618164 C 5.657552 8.46517 5.625 8.300781 5.625 8.125 Z M 11.875 8.125 C 11.875 7.949219 11.907552 7.786459 11.972656 7.636719 C 12.03776 7.486979 12.127277 7.355144 12.241211 7.241211 C 12.355143 7.127279 12.486979 7.037761 12.636719 6.972656 C 12.786457 6.907553 12.949218 6.875001 13.125 6.875 C 13.294271 6.875001 13.455403 6.907553 13.608398 6.972656 C 13.761393 7.037761 13.894856 7.127279 14.008789 7.241211 C 14.122721 7.355144 14.212238 7.488607 14.277344 7.641602 C 14.342447 7.794598 14.375 7.95573 14.375 8.125 C 14.375 8.300781 14.342447 8.463542 14.277344 8.613281 C 14.212238 8.763021 14.122721 8.894857 14.008789 9.008789 C 13.894856 9.122722 13.763021 9.21224 13.613281 9.277344 C 13.463541 9.342448 13.30078 9.375 13.125 9.375 C 12.949218 9.375 12.78483 9.342448 12.631836 9.277344 C 12.478841 9.21224 12.347005 9.12435 12.236328 9.013672 C 12.12565 8.902995 12.03776 8.771159 11.972656 8.618164 C 11.907552 8.46517 11.875 8.300781 11.875 8.125 Z M 5.3125 13.4375 C 5.3125 13.268229 5.374349 13.121745 5.498047 12.998047 C 5.621745 12.87435 5.768229 12.8125 5.9375 12.8125 C 6.041666 12.8125 6.123046 12.827148 6.181641 12.856445 C 6.240234 12.885742 6.305338 12.932943 6.376953 12.998047 C 6.669922 13.245443 6.948242 13.463542 7.211914 13.652344 C 7.475586 13.841146 7.747396 14.000651 8.027344 14.130859 C 8.307291 14.261068 8.606771 14.360352 8.925781 14.428711 C 9.244791 14.49707 9.602864 14.53125 10 14.53125 C 10.572916 14.53125 11.101888 14.448242 11.586914 14.282227 C 12.071939 14.116211 12.542317 13.860678 12.998047 13.515625 C 13.108724 13.43099 13.212891 13.346354 13.310547 13.261719 C 13.408203 13.177084 13.512369 13.089193 13.623047 12.998047 C 13.694661 12.939453 13.759766 12.893881 13.818359 12.861328 C 13.876953 12.828776 13.958333 12.8125 14.0625 12.8125 C 14.231771 12.8125 14.378255 12.87435 14.501953 12.998047 C 14.62565 13.121745 14.6875 13.268229 14.6875 13.4375 C 14.6875 13.528646 14.671224 13.606771 14.638672 13.671875 C 14.606119 13.736979 14.560546 13.805339 14.501953 13.876953 C 14.397786 14.000651 14.269205 14.125977 14.116211 14.25293 C 13.963215 14.379883 13.800455 14.501953 13.62793 14.619141 C 13.455403 14.736328 13.282877 14.845378 13.110352 14.946289 C 12.937825 15.047201 12.779947 15.133464 12.636719 15.205078 C 12.226562 15.413412 11.798502 15.561523 11.352539 15.649414 C 10.906575 15.737305 10.455729 15.78125 10 15.78125 C 9.53125 15.78125 9.070638 15.73405 8.618164 15.639648 C 8.165689 15.545248 7.731119 15.390625 7.314453 15.175781 C 7.229817 15.136719 7.122396 15.079753 6.992188 15.004883 C 6.861979 14.930014 6.723632 14.84375 6.577148 14.746094 C 6.430664 14.648438 6.282552 14.544271 6.132812 14.433594 C 5.983073 14.322917 5.846354 14.210612 5.722656 14.09668 C 5.598958 13.982748 5.499674 13.868815 5.424805 13.754883 C 5.349935 13.640951 5.3125 13.535156 5.3125 13.4375 Z + F1 M 5.625 15 C 4.85026 15 4.121094 14.851889 3.4375 14.555664 C 2.753906 14.25944 2.158203 13.857422 1.650391 13.349609 C 1.142578 12.841797 0.74056 12.246094 0.444336 11.5625 C 0.148112 10.878906 0 10.14974 0 9.375 C 0 8.600261 0.148112 7.871094 0.444336 7.1875 C 0.74056 6.503906 1.142578 5.908203 1.650391 5.400391 C 2.158203 4.892578 2.753906 4.490561 3.4375 4.194336 C 4.121094 3.898113 4.85026 3.75 5.625 3.75 L 8.125 3.75 C 8.294271 3.75 8.440755 3.81185 8.564453 3.935547 C 8.68815 4.059246 8.75 4.20573 8.75 4.375 C 8.75 4.544271 8.68815 4.690756 8.564453 4.814453 C 8.440755 4.938152 8.294271 5.000001 8.125 5 L 5.625 5 C 5.019531 5.000001 4.451497 5.113934 3.920898 5.341797 C 3.390299 5.569662 2.926432 5.882162 2.529297 6.279297 C 2.132161 6.676434 1.819661 7.140301 1.591797 7.670898 C 1.363932 8.201498 1.25 8.769531 1.25 9.375 C 1.25 9.980469 1.363932 10.548503 1.591797 11.079102 C 1.819661 11.609701 2.132161 12.073568 2.529297 12.470703 C 2.926432 12.867839 3.390299 13.180339 3.920898 13.408203 C 4.451497 13.636068 5.019531 13.75 5.625 13.75 L 8.125 13.75 C 8.294271 13.75 8.440755 13.81185 8.564453 13.935547 C 8.68815 14.059245 8.75 14.205729 8.75 14.375 C 8.75 14.544271 8.68815 14.690756 8.564453 14.814453 C 8.440755 14.938151 8.294271 15 8.125 15 Z M 11.875 15 C 11.705729 15 11.559244 14.938151 11.435547 14.814453 C 11.311849 14.690756 11.25 14.544271 11.25 14.375 C 11.25 14.205729 11.311849 14.059245 11.435547 13.935547 C 11.559244 13.81185 11.705729 13.75 11.875 13.75 L 14.375 13.75 C 14.980469 13.75 15.548502 13.636068 16.079102 13.408203 C 16.609699 13.180339 17.073566 12.867839 17.470703 12.470703 C 17.867838 12.073568 18.180338 11.609701 18.408203 11.079102 C 18.636066 10.548503 18.75 9.980469 18.75 9.375 C 18.75 8.769531 18.636066 8.201498 18.408203 7.670898 C 18.180338 7.140301 17.867838 6.676434 17.470703 6.279297 C 17.073566 5.882162 16.609699 5.569662 16.079102 5.341797 C 15.548502 5.113934 14.980469 5.000001 14.375 5 L 11.875 5 C 11.705729 5.000001 11.559244 4.938152 11.435547 4.814453 C 11.311849 4.690756 11.25 4.544271 11.25 4.375 C 11.25 4.20573 11.311849 4.059246 11.435547 3.935547 C 11.559244 3.81185 11.705729 3.75 11.875 3.75 L 14.375 3.75 C 15.149739 3.75 15.878906 3.898113 16.5625 4.194336 C 17.246094 4.490561 17.841797 4.892578 18.349609 5.400391 C 18.857422 5.908203 19.259439 6.503906 19.555664 7.1875 C 19.851887 7.871094 20 8.600261 20 9.375 C 20 10.14974 19.851887 10.878906 19.555664 11.5625 C 19.259439 12.246094 18.857422 12.841797 18.349609 13.349609 C 17.841797 13.857422 17.246094 14.25944 16.5625 14.555664 C 15.878906 14.851889 15.149739 15 14.375 15 Z M 5.556641 10 C 5.38737 10 5.252278 9.934896 5.151367 9.804688 C 5.050456 9.674479 5 9.53125 5 9.375 C 5 9.21875 5.050456 9.075521 5.151367 8.945312 C 5.252278 8.815104 5.38737 8.75 5.556641 8.75 L 14.443359 8.75 C 14.61263 8.75 14.747721 8.815104 14.848633 8.945312 C 14.949543 9.075521 14.999999 9.21875 15 9.375 C 14.999999 9.53125 14.949543 9.674479 14.848633 9.804688 C 14.747721 9.934896 14.61263 10 14.443359 10 Z + F1 M 0.625 17.5 C 0.455729 17.5 0.309245 17.43815 0.185547 17.314453 C 0.061849 17.190756 0 17.044271 0 16.875 C 0 16.829428 0.035807 16.689453 0.107422 16.455078 C 0.179036 16.220703 0.268555 15.9375 0.375977 15.605469 C 0.483398 15.273438 0.600586 14.916992 0.727539 14.536133 C 0.854492 14.155273 0.976562 13.79069 1.09375 13.442383 C 1.210938 13.094076 1.315104 12.788086 1.40625 12.524414 C 1.497396 12.260742 1.559245 12.083334 1.591797 11.992188 C 1.617839 11.907553 1.669922 11.826172 1.748047 11.748047 L 12.529297 0.966797 C 12.815755 0.68034 13.146158 0.458984 13.520508 0.302734 C 13.894856 0.146484 14.283854 0.068359 14.6875 0.068359 C 15.104166 0.068359 15.498047 0.148113 15.869141 0.307617 C 16.240234 0.467123 16.565754 0.68685 16.845703 0.966797 C 17.12565 1.246746 17.345377 1.572266 17.504883 1.943359 C 17.664387 2.314453 17.744141 2.708334 17.744141 3.125 C 17.744141 3.535156 17.666016 3.924154 17.509766 4.291992 C 17.353516 4.659831 17.13216 4.990234 16.845703 5.283203 L 15.263672 6.875 C 15.524088 7.161459 15.727539 7.444662 15.874023 7.724609 C 16.020508 8.004558 16.09375 8.346354 16.09375 8.75 C 16.09375 9.082031 16.030273 9.401042 15.90332 9.707031 C 15.776367 10.013021 15.595703 10.283203 15.361328 10.517578 L 13.564453 12.314453 C 13.440755 12.438151 13.294271 12.5 13.125 12.5 C 12.955729 12.5 12.809244 12.438151 12.685547 12.314453 C 12.561849 12.190756 12.5 12.044271 12.5 11.875 C 12.5 11.705729 12.561849 11.559245 12.685547 11.435547 L 14.482422 9.638672 C 14.729816 9.391276 14.853515 9.095053 14.853516 8.75 C 14.853515 8.548178 14.811197 8.365886 14.726562 8.203125 C 14.641927 8.040365 14.524739 7.893881 14.375 7.763672 L 6.064453 16.064453 C 5.979817 16.14909 5.885417 16.204428 5.78125 16.230469 L 0.78125 17.480469 C 0.716146 17.49349 0.664062 17.5 0.625 17.5 Z M 1.582031 15.996094 L 5.302734 15.058594 L 15.966797 4.404297 C 16.136066 4.235027 16.266275 4.039715 16.357422 3.818359 C 16.448566 3.597006 16.494141 3.365887 16.494141 3.125 C 16.494141 2.871094 16.446939 2.635092 16.352539 2.416992 C 16.258137 2.198895 16.129557 2.008465 15.966797 1.845703 C 15.804036 1.682943 15.613606 1.554363 15.395508 1.459961 C 15.177408 1.365561 14.941406 1.318359 14.6875 1.318359 C 14.446613 1.318359 14.215494 1.363934 13.994141 1.455078 C 13.772786 1.546225 13.577474 1.676434 13.408203 1.845703 L 2.734375 12.529297 Z M 1.523438 18.583984 L 3.203125 18.164062 C 3.580729 18.352865 3.972982 18.497721 4.379883 18.598633 C 4.786784 18.699545 5.201823 18.75 5.625 18.75 C 6.067708 18.75 6.500651 18.6556 6.923828 18.466797 C 7.347005 18.277994 7.762044 18.041992 8.168945 17.758789 C 8.575846 17.475586 8.976236 17.169596 9.370117 16.84082 C 9.763997 16.512045 10.151367 16.206055 10.532227 15.922852 C 10.913086 15.639648 11.287435 15.403646 11.655273 15.214844 C 12.023111 15.026042 12.386067 14.931641 12.744141 14.931641 C 12.952474 14.931641 13.144531 14.964193 13.320312 15.029297 C 13.59375 15.126953 13.818359 15.255534 13.994141 15.415039 C 14.169922 15.574545 14.316406 15.753581 14.433594 15.952148 C 14.550781 16.150717 14.650064 16.367188 14.731445 16.601562 C 14.812824 16.835938 14.892577 17.076824 14.970703 17.324219 C 15.003255 17.434896 15.0472 17.542318 15.102539 17.646484 C 15.157877 17.75065 15.224609 17.845053 15.302734 17.929688 C 15.341797 17.97526 15.388997 18.019205 15.444336 18.061523 C 15.499674 18.103842 15.559895 18.125 15.625 18.125 C 15.768229 18.125 15.939127 18.081055 16.137695 17.993164 C 16.336262 17.905273 16.536457 17.799479 16.738281 17.675781 C 16.940104 17.552084 17.133789 17.425131 17.319336 17.294922 C 17.504883 17.164713 17.659504 17.057291 17.783203 16.972656 C 17.978516 16.842449 18.185221 16.722006 18.40332 16.611328 C 18.621418 16.50065 18.8444 16.402994 19.072266 16.318359 C 19.182941 16.272787 19.283854 16.25 19.375 16.25 C 19.550781 16.25 19.698893 16.310223 19.819336 16.430664 C 19.939777 16.551107 20 16.699219 20 16.875 C 20 17.011719 19.957682 17.135416 19.873047 17.246094 C 19.78841 17.356771 19.680988 17.431641 19.550781 17.470703 C 19.54427 17.483725 19.524738 17.490234 19.492188 17.490234 C 19.186197 17.613932 18.873697 17.781576 18.554688 17.993164 C 18.235676 18.204752 17.91341 18.413086 17.587891 18.618164 C 17.262369 18.823242 16.935221 19.00065 16.606445 19.150391 C 16.277668 19.300131 15.95052 19.375 15.625 19.375 C 15.371094 19.375 15.139974 19.319662 14.931641 19.208984 C 14.723307 19.098307 14.534504 18.948568 14.365234 18.759766 C 14.215494 18.597006 14.09668 18.427734 14.008789 18.251953 C 13.920898 18.076172 13.8444 17.884115 13.779297 17.675781 C 13.740234 17.558594 13.694661 17.415365 13.642578 17.246094 C 13.590494 17.076822 13.523762 16.914062 13.442383 16.757812 C 13.361002 16.601562 13.263346 16.4681 13.149414 16.357422 C 13.03548 16.246746 12.90039 16.191406 12.744141 16.191406 C 12.496744 16.191406 12.223307 16.285809 11.923828 16.474609 C 11.624349 16.663412 11.298828 16.897787 10.947266 17.177734 C 10.595703 17.457682 10.218099 17.763672 9.814453 18.095703 C 9.410807 18.427734 8.986002 18.733725 8.540039 19.013672 C 8.094075 19.293619 7.626953 19.527994 7.138672 19.716797 C 6.650391 19.9056 6.145833 20 5.625 20 C 4.902344 20 4.192708 19.881186 3.496094 19.643555 C 2.799479 19.405924 2.161458 19.06901 1.582031 18.632812 Z + + + M1024,317.5L1024,507C1014.67,495.333 1004.67,484.167 994,473.5C983.333,462.833 972,453 960,444L960,320C960,311.333 958.333,303.083 955,295.25C951.667,287.417 947.083,280.583 941.25,274.75C935.417,268.917 928.583,264.333 920.75,261C912.917,257.667 904.667,256 896,256L522,256L458,298.5C436,312.833 412.333,320 387,320L64,320L64,832C64,841 65.6667,849.417 69,857.25C72.3333,865.083 76.8333,871.833 82.5,877.5C88.1667,883.167 94.9167,887.667 102.75,891C110.583,894.333 119,896 128,896L404.5,896C410.167,907.333 416.25,918.333 422.75,929C429.25,939.667 436.333,950 444,960L125.5,960C108.833,960 92.9167,956.583 77.75,949.75C62.5833,942.917 49.25,933.75 37.75,922.25C26.25,910.75 17.0833,897.417 10.25,882.25C3.41667,867.083 0,851.167 0,834.5L0,189.5C0,172.833 3.41667,156.917 10.25,141.75C17.0833,126.583 26.25,113.25 37.75,101.75C49.25,90.25 62.5833,81.0834 77.75,74.25C92.9167,67.4167 108.833,64.0001 125.5,64L368,64C388,64.0001 407.167,68.5001 425.5,77.5C443.833,86.5001 458.833,99.0001 470.5,115L528,192L898.5,192C915.167,192 931.083,195.417 946.25,202.25C961.417,209.083 974.75,218.25 986.25,229.75C997.75,241.25 1006.92,254.583 1013.75,269.75C1020.58,284.917 1024,300.833 1024,317.5ZM466,216L419,153.5C413,145.5 405.5,139.25 396.5,134.75C387.5,130.25 378,128 368,128L128,128C119,128 110.667,129.667 103,133C95.3333,136.333 88.5833,140.917 82.75,146.75C76.9167,152.583 72.3333,159.333 69,167C65.6667,174.667 64,183 64,192L64,256L387,256C394.333,256 401.5,254.667 408.5,252C415.5,249.333 422.25,246 428.75,242C435.25,238 441.583,233.667 447.75,229C453.917,224.333 460,220 466,216ZM1024,736C1024,775.667 1016.42,813 1001.25,848C986.083,883 965.5,913.5 939.5,939.5C913.5,965.5 883,986.083 848,1001.25C813,1016.42 775.667,1024 736,1024C696,1024 658.5,1016.5 623.5,1001.5C588.5,986.5 558,966 532,940C506,914 485.5,883.5 470.5,848.5C455.5,813.5 448,776 448,736C448,696.333 455.583,659 470.75,624C485.917,589 506.5,558.5 532.5,532.5C558.5,506.5 589,485.917 624,470.75C659,455.583 696.333,448 736,448C762.333,448 787.75,451.417 812.25,458.25C836.75,465.083 859.667,474.75 881,487.25C902.333,499.75 921.833,514.833 939.5,532.5C957.167,550.167 972.25,569.667 984.75,591C997.25,612.333 1006.92,635.25 1013.75,659.75C1020.58,684.25 1024,709.667 1024,736ZM896,576C896,567.333 892.833,559.833 886.5,553.5C880.167,547.167 872.667,544 864,544C857.667,544 852.5,545.167 848.5,547.5C844.5,549.833 841.25,552.917 838.75,556.75C836.25,560.583 834.5,565 833.5,570C832.5,575 832,580.167 832,585.5C816.333,577.167 800.917,570.833 785.75,566.5C770.583,562.167 754,560 736,560C724,560 711.75,561.25 699.25,563.75C686.75,566.25 674.5,569.917 662.5,574.75C650.5,579.583 639.083,585.417 628.25,592.25C617.417,599.083 608,607 600,616C597,619.333 594.667,622.75 593,626.25C591.333,629.75 590.5,633.833 590.5,638.5C590.5,647.5 593.667,655.167 600,661.5C606.333,667.833 614,671 623,671C628.667,671 634.75,668.583 641.25,663.75C647.75,658.917 655.333,653.5 664,647.5C672.667,641.5 682.75,636.083 694.25,631.25C705.75,626.417 719.333,624 735,624C746.667,624 757.5,625.25 767.5,627.75C777.5,630.25 787.667,634.333 798,640L785,640C779,640 773.083,640.25 767.25,640.75C761.417,641.25 756.167,642.583 751.5,644.75C746.833,646.917 743.083,650.167 740.25,654.5C737.417,658.833 736,664.667 736,672C736,680.667 739.167,688.167 745.5,694.5C751.833,700.833 759.333,704 768,704L864,704C872.667,704 880.167,700.833 886.5,694.5C892.833,688.167 896,680.667 896,672ZM881.5,833C881.5,824.333 878.333,816.833 872,810.5C865.667,804.167 858.167,801 849.5,801C842.833,801 836.333,803.417 830,808.25C823.667,813.083 816.333,818.5 808,824.5C799.667,830.5 789.833,835.917 778.5,840.75C767.167,845.583 753.333,848 737,848C725.333,848 714.5,846.75 704.5,844.25C694.5,841.75 684.333,837.667 674,832L687,832C692.667,832 698.417,831.75 704.25,831.25C710.083,830.75 715.333,829.417 720,827.25C724.667,825.083 728.5,821.833 731.5,817.5C734.5,813.167 736,807.333 736,800C736,791.333 732.833,783.833 726.5,777.5C720.167,771.167 712.667,768 704,768L608,768C599.333,768 591.833,771.167 585.5,777.5C579.167,783.833 576,791.333 576,800L576,896C576,904.667 579.167,912.167 585.5,918.5C591.833,924.833 599.333,928 608,928C614.333,928 619.5,926.833 623.5,924.5C627.5,922.167 630.75,919.083 633.25,915.25C635.75,911.417 637.5,907 638.5,902C639.5,897 640,891.833 640,886.5C655.667,894.833 671.083,901.167 686.25,905.5C701.417,909.833 718,912 736,912C748,912 760.333,910.75 773,908.25C785.667,905.75 797.917,902.083 809.75,897.25C821.583,892.417 832.833,886.583 843.5,879.75C854.167,872.917 863.667,865 872,856C878.333,849.333 881.5,841.667 881.5,833Z + M128,220C128,190 134.083,161.667 146.25,135C158.417,108.333 174.75,85 195.25,65C215.75,45 239.5,29.1667 266.5,17.5C293.5,5.83337 322,0 352,0C382.667,0 411.583,5.91669 438.75,17.75C465.917,29.5834 489.667,45.6667 510,66C530.333,86.3334 546.417,110.083 558.25,137.25C570.083,164.417 576,193.333 576,224C576,254.667 570.083,283.583 558.25,310.75C546.417,337.917 530.333,361.667 510,382C489.667,402.333 465.917,418.417 438.75,430.25C411.583,442.083 382.667,448 352,448C320.333,448 290.833,442 263.5,430C236.167,418 212.5,401.667 192.5,381C172.5,360.333 156.75,336.167 145.25,308.5C133.75,280.833 128,251.333 128,220ZM512,220.5C512,198.833 507.667,178.5 499,159.5C490.333,140.5 478.667,123.917 464,109.75C449.333,95.5834 432.333,84.4167 413,76.25C393.667,68.0834 373.333,64.0001 352,64C329.667,64.0001 308.833,68.1667 289.5,76.5C270.167,84.8334 253.25,96.25 238.75,110.75C224.25,125.25 212.833,142.167 204.5,161.5C196.167,180.833 192,201.667 192,224C192,246.333 196.167,267.167 204.5,286.5C212.833,305.833 224.25,322.75 238.75,337.25C253.25,351.75 270.167,363.167 289.5,371.5C308.833,379.833 329.667,384 352,384C375,384 396.25,379.75 415.75,371.25C435.25,362.75 452.167,351.083 466.5,336.25C480.833,321.417 492,304.083 500,284.25C508,264.417 512,243.167 512,220.5ZM640,284.5C640,262.833 644.333,242.5 653,223.5C661.667,204.5 673.333,187.917 688,173.75C702.667,159.583 719.667,148.417 739,140.25C758.333,132.083 778.667,128 800,128C822.333,128 843.167,132.167 862.5,140.5C881.833,148.833 898.75,160.25 913.25,174.75C927.75,189.25 939.167,206.167 947.5,225.5C955.833,244.833 960,265.667 960,288C960,310.333 955.833,331.167 947.5,350.5C939.167,369.833 927.75,386.75 913.25,401.25C898.75,415.75 881.833,427.167 862.5,435.5C843.167,443.833 822.333,448 800,448C777,448 755.75,443.75 736.25,435.25C716.75,426.75 699.833,415.083 685.5,400.25C671.167,385.417 660,368.083 652,348.25C644,328.417 640,307.167 640,284.5ZM896,288C896,275 893.5,262.667 888.5,251C883.5,239.333 876.583,229.083 867.75,220.25C858.917,211.417 848.667,204.5 837,199.5C825.333,194.5 813,192 800,192C787,192 774.667,194.5 763,199.5C751.333,204.5 741.083,211.417 732.25,220.25C723.417,229.083 716.5,239.333 711.5,251C706.5,262.667 704,275 704,288C704,301 706.5,313.333 711.5,325C716.5,336.667 723.417,346.917 732.25,355.75C741.083,364.583 751.333,371.5 763,376.5C774.667,381.5 787,384 800,384C813,384 825.333,381.5 837,376.5C848.667,371.5 858.917,364.583 867.75,355.75C876.583,346.917 883.5,336.667 888.5,325C893.5,313.333 896,301 896,288ZM0,638C0,623.667 2.41667,609 7.25,594C12.0833,579 19,565.417 28,553.25C37,541.083 47.9167,531.167 60.75,523.5C73.5833,515.833 88,512 104,512L600,512C616,512 630.417,515.833 643.25,523.5C656.083,531.167 667,541.083 676,553.25C685,565.417 691.917,579 696.75,594C701.583,609 704,623.667 704,638C704,667 701,694.917 695,721.75C689,748.583 679.75,773.833 667.25,797.5C654.75,821.167 639.083,842.917 620.25,862.75C601.417,882.583 579.167,899.833 553.5,914.5C538.5,923.167 522.75,930.417 506.25,936.25C489.75,942.083 473,946.75 456,950.25C439,953.75 421.75,956.25 404.25,957.75C386.75,959.25 369.333,960 352,960C317,960 282.333,956.833 248,950.5C213.667,944.167 181.167,932.167 150.5,914.5C124.5,899.5 102.083,882.167 83.25,862.5C64.4167,842.833 48.8333,821.25 36.5,797.75C24.1667,774.25 15,749.083 9,722.25C3,695.417 0,667.333 0,638ZM698.5,896C714.833,876.333 728.833,854.5 740.5,830.5C771.5,828.167 800.417,822.417 827.25,813.25C854.083,804.083 877.333,791.083 897,774.25C916.667,757.417 932.083,736.583 943.25,711.75C954.417,686.917 960,657.667 960,624C960,619 959.25,613.75 957.75,608.25C956.25,602.75 954.083,597.583 951.25,592.75C948.417,587.917 944.833,583.917 940.5,580.75C936.167,577.583 931.167,576 925.5,576L775,576C771.333,564.667 767,553.583 762,542.75C757,531.917 751.167,521.667 744.5,512L925.5,512C940.167,512 953.583,515.25 965.75,521.75C977.917,528.25 988.333,536.75 997,547.25C1005.67,557.75 1012.33,569.75 1017,583.25C1021.67,596.75 1024,610.333 1024,624C1024,675.333 1012.5,720.833 989.5,760.5C966.5,800.167 932.333,832.333 887,857C858.333,872.667 827.833,883.083 795.5,888.25C763.167,893.417 730.833,896 698.5,896ZM640,640C640,634.333 639.167,627.75 637.5,620.25C635.833,612.75 633.25,605.75 629.75,599.25C626.25,592.75 621.833,587.25 616.5,582.75C611.167,578.25 605,576 598,576L106,576C99,576 92.8333,578.25 87.5,582.75C82.1667,587.25 77.75,592.75 74.25,599.25C70.75,605.75 68.1667,612.75 66.5,620.25C64.8333,627.75 64,634.333 64,640C64,684.333 71.25,722.583 85.75,754.75C100.25,786.917 120.333,813.5 146,834.5C171.667,855.5 202.083,871 237.25,881C272.417,891 310.667,896 352,896C393.333,896 431.583,891 466.75,881C501.917,871 532.333,855.5 558,834.5C583.667,813.5 603.75,786.917 618.25,754.75C632.75,722.583 640,684.333 640,640Z + + + F1 M 8.75 10.625 C 8.75 10.455729 8.811849 10.309245 8.935547 10.185547 L 16.621094 2.5 L 10.625 2.5 C 10.455729 2.5 10.309244 2.438152 10.185547 2.314453 C 10.061849 2.190756 10 2.044271 10 1.875 C 10 1.70573 10.061849 1.559246 10.185547 1.435547 C 10.309244 1.31185 10.455729 1.25 10.625 1.25 L 18.125 1.25 C 18.29427 1.25 18.440754 1.31185 18.564453 1.435547 C 18.68815 1.559246 18.75 1.70573 18.75 1.875 L 18.75 9.375 C 18.75 9.544271 18.68815 9.690756 18.564453 9.814453 C 18.440754 9.938151 18.29427 10 18.125 10 C 17.955729 10 17.809244 9.938151 17.685547 9.814453 C 17.561848 9.690756 17.5 9.544271 17.5 9.375 L 17.5 3.388672 L 9.814453 11.064453 C 9.749349 11.123047 9.682617 11.16862 9.614258 11.201172 C 9.545898 11.233725 9.466146 11.25 9.375 11.25 C 9.205729 11.25 9.059244 11.188151 8.935547 11.064453 C 8.811849 10.940756 8.75 10.794271 8.75 10.625 Z M 4.921875 18.75 C 4.433594 18.75 3.966471 18.650717 3.520508 18.452148 C 3.074544 18.25358 2.683919 17.986654 2.348633 17.651367 C 2.013346 17.31608 1.746419 16.925455 1.547852 16.479492 C 1.349284 16.033529 1.25 15.566406 1.25 15.078125 L 1.25 6.171875 C 1.25 5.683595 1.349284 5.216473 1.547852 4.770508 C 1.746419 4.324545 2.013346 3.93392 2.348633 3.598633 C 2.683919 3.263348 3.074544 2.99642 3.520508 2.797852 C 3.966471 2.599285 4.433594 2.5 4.921875 2.5 L 8.125 2.5 C 8.294271 2.5 8.440755 2.56185 8.564453 2.685547 C 8.68815 2.809246 8.75 2.95573 8.75 3.125 C 8.75 3.294271 8.68815 3.440756 8.564453 3.564453 C 8.440755 3.688152 8.294271 3.75 8.125 3.75 L 4.951172 3.75 C 4.625651 3.75 4.314778 3.816732 4.018555 3.950195 C 3.722331 4.08366 3.461914 4.262696 3.237305 4.487305 C 3.012695 4.711915 2.833659 4.972332 2.700195 5.268555 C 2.566732 5.564779 2.5 5.875651 2.5 6.201172 L 2.5 15.048828 C 2.5 15.37435 2.566732 15.685222 2.700195 15.981445 C 2.833659 16.27767 3.012695 16.538086 3.237305 16.762695 C 3.461914 16.987305 3.722331 17.166342 4.018555 17.299805 C 4.314778 17.433268 4.625651 17.5 4.951172 17.5 L 13.798828 17.5 C 14.137369 17.5 14.454752 17.431641 14.750977 17.294922 C 15.0472 17.158203 15.305989 16.975912 15.527344 16.748047 C 15.748697 16.520182 15.924479 16.254883 16.054688 15.952148 C 16.184895 15.649414 16.25 15.332031 16.25 15 L 16.25 11.875 C 16.25 11.705729 16.311848 11.559245 16.435547 11.435547 C 16.559244 11.31185 16.705729 11.25 16.875 11.25 C 17.04427 11.25 17.190754 11.31185 17.314453 11.435547 C 17.43815 11.559245 17.5 11.705729 17.5 11.875 L 17.5 15.078125 C 17.5 15.566406 17.400715 16.033529 17.202148 16.479492 C 17.00358 16.925455 16.736652 17.31608 16.401367 17.651367 C 16.06608 17.986654 15.675455 18.25358 15.229492 18.452148 C 14.783527 18.650717 14.316405 18.75 13.828125 18.75 Z + diff --git a/Wino.Mail.WinUI/Styles/ImagePreviewControl.xaml b/Wino.Mail.WinUI/Styles/ImagePreviewControl.xaml new file mode 100644 index 00000000..67ad57f5 --- /dev/null +++ b/Wino.Mail.WinUI/Styles/ImagePreviewControl.xaml @@ -0,0 +1,44 @@ + + + + diff --git a/Wino.Mail.WinUI/Styles/ItemContainerStyles.xaml b/Wino.Mail.WinUI/Styles/ItemContainerStyles.xaml new file mode 100644 index 00000000..9b85d77b --- /dev/null +++ b/Wino.Mail.WinUI/Styles/ItemContainerStyles.xaml @@ -0,0 +1,304 @@ + + + + + #34495e + + + + #ecf0f1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wino.Mail.WinUI/Styles/WinoInfoBar.xaml b/Wino.Mail.WinUI/Styles/WinoInfoBar.xaml new file mode 100644 index 00000000..07eb899f --- /dev/null +++ b/Wino.Mail.WinUI/Styles/WinoInfoBar.xaml @@ -0,0 +1,422 @@ + + + + #74b9ff + + + + + + + + + + + + + + + + + + + + + + 1 + + + + #3867d6 + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + 2 + + + + 14 + SemiBold + + 14 + Normal + + 48 + + 38 + 16 + + + -12,0,0,0 + + + + + + + + 16,0,0,0 + + 0,16,14,16 + 16 + + 0,0,16,0 + 0,0,0,0 + 0,14,0,18 + + 0,14,0,0 + 0,14,0,0 + + 12,14,0,0 + 0,4,0,0 + + 16,8,0,0 + 0,12,0,0 + + Cancel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wino.Mail.WinUI/Views/Abstract/AboutPageAbstract.cs b/Wino.Mail.WinUI/Views/Abstract/AboutPageAbstract.cs new file mode 100644 index 00000000..16d785c5 --- /dev/null +++ b/Wino.Mail.WinUI/Views/Abstract/AboutPageAbstract.cs @@ -0,0 +1,8 @@ +using Wino.Mail.ViewModels; + +namespace Wino.Views.Abstract +{ + public abstract class AboutPageAbstract : BasePage + { + } +} diff --git a/Wino.Mail.WinUI/Views/Abstract/AccountDetailsPageAbstract.cs b/Wino.Mail.WinUI/Views/Abstract/AccountDetailsPageAbstract.cs new file mode 100644 index 00000000..036ff394 --- /dev/null +++ b/Wino.Mail.WinUI/Views/Abstract/AccountDetailsPageAbstract.cs @@ -0,0 +1,8 @@ +using Wino.Mail.ViewModels; + +namespace Wino.Views.Abstract +{ + public abstract class AccountDetailsPageAbstract : BasePage + { + } +} diff --git a/Wino.Mail.WinUI/Views/Abstract/AccountManagementPageAbstract.cs b/Wino.Mail.WinUI/Views/Abstract/AccountManagementPageAbstract.cs new file mode 100644 index 00000000..1b6f6a72 --- /dev/null +++ b/Wino.Mail.WinUI/Views/Abstract/AccountManagementPageAbstract.cs @@ -0,0 +1,9 @@ +using Wino.Mail.ViewModels; + +namespace Wino.Views.Abstract +{ + public abstract class AccountManagementPageAbstract : BasePage + { + + } +} diff --git a/Wino.Mail.WinUI/Views/Abstract/AppShellAbstract.cs b/Wino.Mail.WinUI/Views/Abstract/AppShellAbstract.cs new file mode 100644 index 00000000..5817c572 --- /dev/null +++ b/Wino.Mail.WinUI/Views/Abstract/AppShellAbstract.cs @@ -0,0 +1,8 @@ +using Wino.Mail.ViewModels; + +namespace Wino.Views.Abstract +{ + public abstract class AppShellAbstract : BasePage + { + } +} diff --git a/Wino.Mail.WinUI/Views/Abstract/ComposePageAbstract.cs b/Wino.Mail.WinUI/Views/Abstract/ComposePageAbstract.cs new file mode 100644 index 00000000..fbe85077 --- /dev/null +++ b/Wino.Mail.WinUI/Views/Abstract/ComposePageAbstract.cs @@ -0,0 +1,8 @@ +using Wino.Mail.ViewModels; + +namespace Wino.Views.Abstract +{ + public abstract class ComposePageAbstract : BasePage + { + } +} diff --git a/Wino.Mail.WinUI/Views/Abstract/IdlePageAbstract.cs b/Wino.Mail.WinUI/Views/Abstract/IdlePageAbstract.cs new file mode 100644 index 00000000..9e28d8ff --- /dev/null +++ b/Wino.Mail.WinUI/Views/Abstract/IdlePageAbstract.cs @@ -0,0 +1,8 @@ +using Wino.Mail.ViewModels; + +namespace Wino.Views.Abstract +{ + public abstract class IdlePageAbstract : BasePage + { + } +} diff --git a/Wino.Mail.WinUI/Views/Abstract/LanguageTimePageAbstract.cs b/Wino.Mail.WinUI/Views/Abstract/LanguageTimePageAbstract.cs new file mode 100644 index 00000000..492966d4 --- /dev/null +++ b/Wino.Mail.WinUI/Views/Abstract/LanguageTimePageAbstract.cs @@ -0,0 +1,6 @@ +using Wino.Mail.ViewModels; + +namespace Wino.Views.Abstract +{ + public abstract class LanguageTimePageAbstract : BasePage { } +} diff --git a/Wino.Mail.WinUI/Views/Abstract/MailListPageAbstract.cs b/Wino.Mail.WinUI/Views/Abstract/MailListPageAbstract.cs new file mode 100644 index 00000000..70a4cb4c --- /dev/null +++ b/Wino.Mail.WinUI/Views/Abstract/MailListPageAbstract.cs @@ -0,0 +1,9 @@ +using Wino.Mail.ViewModels; + +namespace Wino.Views.Abstract +{ + public class MailListPageAbstract : BasePage + { + + } +} diff --git a/Wino.Mail.WinUI/Views/Abstract/MailRenderingPageAbstract.cs b/Wino.Mail.WinUI/Views/Abstract/MailRenderingPageAbstract.cs new file mode 100644 index 00000000..761712f4 --- /dev/null +++ b/Wino.Mail.WinUI/Views/Abstract/MailRenderingPageAbstract.cs @@ -0,0 +1,26 @@ +using Microsoft.UI.Xaml; +using Wino.Mail.ViewModels; + +namespace Wino.Views.Abstract +{ + public abstract class MailRenderingPageAbstract : BasePage + { + public bool IsDarkEditor + { + get { return (bool)GetValue(IsDarkEditorProperty); } + set { SetValue(IsDarkEditorProperty, value); } + } + + public static readonly DependencyProperty IsDarkEditorProperty = DependencyProperty.Register(nameof(IsDarkEditor), typeof(bool), typeof(MailRenderingPageAbstract), new PropertyMetadata(false, OnIsComposerDarkModeChanged)); + + private static void OnIsComposerDarkModeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) + { + if (obj is MailRenderingPageAbstract page) + { + page.OnEditorThemeChanged(); + } + } + + public virtual void OnEditorThemeChanged() { } + } +} diff --git a/Wino.Mail.WinUI/Views/Abstract/MergedAccountDetailsPageAbstract.cs b/Wino.Mail.WinUI/Views/Abstract/MergedAccountDetailsPageAbstract.cs new file mode 100644 index 00000000..29f1a364 --- /dev/null +++ b/Wino.Mail.WinUI/Views/Abstract/MergedAccountDetailsPageAbstract.cs @@ -0,0 +1,8 @@ +using Wino.Mail.ViewModels; + +namespace Wino.Views.Abstract +{ + public abstract class MergedAccountDetailsPageAbstract : BasePage + { + } +} diff --git a/Wino.Mail.WinUI/Views/Abstract/MessageListPageAbstract.cs b/Wino.Mail.WinUI/Views/Abstract/MessageListPageAbstract.cs new file mode 100644 index 00000000..d474c4be --- /dev/null +++ b/Wino.Mail.WinUI/Views/Abstract/MessageListPageAbstract.cs @@ -0,0 +1,6 @@ +using Wino.Mail.ViewModels; + +namespace Wino.Views.Abstract +{ + public abstract class MessageListPageAbstract : BasePage { } +} diff --git a/Wino.Mail.WinUI/Views/Abstract/NewAccountManagementPageAbstract.cs b/Wino.Mail.WinUI/Views/Abstract/NewAccountManagementPageAbstract.cs new file mode 100644 index 00000000..cdd8b272 --- /dev/null +++ b/Wino.Mail.WinUI/Views/Abstract/NewAccountManagementPageAbstract.cs @@ -0,0 +1,8 @@ +using Wino.Mail.ViewModels; + +namespace Wino.Views.Abstract +{ + public abstract class NewAccountManagementPageAbstract : BasePage + { + } +} diff --git a/Wino.Mail.WinUI/Views/Abstract/PersonalizationPageAbstract.cs b/Wino.Mail.WinUI/Views/Abstract/PersonalizationPageAbstract.cs new file mode 100644 index 00000000..ca4d0da0 --- /dev/null +++ b/Wino.Mail.WinUI/Views/Abstract/PersonalizationPageAbstract.cs @@ -0,0 +1,10 @@ +using Windows.UI.Xaml; +using Wino.Mail.ViewModels; + +namespace Wino.Views.Abstract +{ + public abstract class PersonalizationPageAbstract : SettingsPageBase + { + + } +} diff --git a/Wino.Mail.WinUI/Views/Abstract/ReadingPanePageAbstract.cs b/Wino.Mail.WinUI/Views/Abstract/ReadingPanePageAbstract.cs new file mode 100644 index 00000000..01ab1f48 --- /dev/null +++ b/Wino.Mail.WinUI/Views/Abstract/ReadingPanePageAbstract.cs @@ -0,0 +1,6 @@ +using Wino.Mail.ViewModels; + +namespace Wino.Views.Abstract +{ + public abstract class ReadingPanePageAbstract : BasePage { } +} diff --git a/Wino.Mail.WinUI/Views/Abstract/SettingOptionsPageAbstract.cs b/Wino.Mail.WinUI/Views/Abstract/SettingOptionsPageAbstract.cs new file mode 100644 index 00000000..c9939223 --- /dev/null +++ b/Wino.Mail.WinUI/Views/Abstract/SettingOptionsPageAbstract.cs @@ -0,0 +1,8 @@ +using Wino.Mail.ViewModels; + +namespace Wino.Views.Abstract +{ + public abstract class SettingOptionsPageAbstract : SettingsPageBase + { + } +} diff --git a/Wino.Mail.WinUI/Views/Abstract/SettingsPageAbstract.cs b/Wino.Mail.WinUI/Views/Abstract/SettingsPageAbstract.cs new file mode 100644 index 00000000..5abe8aed --- /dev/null +++ b/Wino.Mail.WinUI/Views/Abstract/SettingsPageAbstract.cs @@ -0,0 +1,6 @@ +using Wino.Mail.ViewModels; + +namespace Wino.Views.Abstract +{ + public abstract class SettingsPageAbstract : BasePage { } +} diff --git a/Wino.Mail.WinUI/Views/Abstract/SettingsPageBase.cs b/Wino.Mail.WinUI/Views/Abstract/SettingsPageBase.cs new file mode 100644 index 00000000..bfec3aa2 --- /dev/null +++ b/Wino.Mail.WinUI/Views/Abstract/SettingsPageBase.cs @@ -0,0 +1,16 @@ +using Microsoft.UI.Xaml; +using Wino.Mail.ViewModels; + +namespace Wino.Views.Abstract +{ + public class SettingsPageBase : BasePage where T : BaseViewModel + { + public string Title + { + get { return (string)GetValue(TitleProperty); } + set { SetValue(TitleProperty, value); } + } + + public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(nameof(Title), typeof(string), typeof(SettingsPageBase), new PropertyMetadata(string.Empty)); + } +} diff --git a/Wino.Mail.WinUI/Views/Abstract/SignatureManagementPageAbstract.cs b/Wino.Mail.WinUI/Views/Abstract/SignatureManagementPageAbstract.cs new file mode 100644 index 00000000..22936f9c --- /dev/null +++ b/Wino.Mail.WinUI/Views/Abstract/SignatureManagementPageAbstract.cs @@ -0,0 +1,6 @@ +using Wino.Mail.ViewModels; + +namespace Wino.Views.Abstract +{ + public abstract class SignatureManagementPageAbstract : BasePage { } +} diff --git a/Wino.Mail.WinUI/Views/Abstract/WelcomePageAbstract.cs b/Wino.Mail.WinUI/Views/Abstract/WelcomePageAbstract.cs new file mode 100644 index 00000000..17959876 --- /dev/null +++ b/Wino.Mail.WinUI/Views/Abstract/WelcomePageAbstract.cs @@ -0,0 +1,9 @@ +using Wino.Mail.ViewModels; + +namespace Wino.Views.Abstract +{ + public abstract class WelcomePageAbstract : BasePage + { + + } +} diff --git a/Wino.Mail.WinUI/Views/Account/AccountDetailsPage.xaml b/Wino.Mail.WinUI/Views/Account/AccountDetailsPage.xaml new file mode 100644 index 00000000..f48bc48c --- /dev/null +++ b/Wino.Mail.WinUI/Views/Account/AccountDetailsPage.xaml @@ -0,0 +1,213 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wino.Mail.WinUI/Views/Account/AccountManagementPage.xaml.cs b/Wino.Mail.WinUI/Views/Account/AccountManagementPage.xaml.cs new file mode 100644 index 00000000..0b27f4cc --- /dev/null +++ b/Wino.Mail.WinUI/Views/Account/AccountManagementPage.xaml.cs @@ -0,0 +1,20 @@ +using Wino.Views.Abstract; + +#if NET8_0 +using Microsoft.UI.Xaml.Navigation; +#else +using Windows.UI.Xaml.Navigation; +#endif + +namespace Wino.Views +{ + public sealed partial class AccountManagementPage : AccountManagementPageAbstract + { + public AccountManagementPage() + { + InitializeComponent(); + + NavigationCacheMode = NavigationCacheMode.Enabled; + } + } +} diff --git a/Wino.Mail.WinUI/Views/Account/MergedAccountDetailsPage.xaml b/Wino.Mail.WinUI/Views/Account/MergedAccountDetailsPage.xaml new file mode 100644 index 00000000..405205e7 --- /dev/null +++ b/Wino.Mail.WinUI/Views/Account/MergedAccountDetailsPage.xaml @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wino.Mail.WinUI/Views/Account/MergedAccountDetailsPage.xaml.cs b/Wino.Mail.WinUI/Views/Account/MergedAccountDetailsPage.xaml.cs new file mode 100644 index 00000000..fa552a4c --- /dev/null +++ b/Wino.Mail.WinUI/Views/Account/MergedAccountDetailsPage.xaml.cs @@ -0,0 +1,12 @@ +using Wino.Views.Abstract; + +namespace Wino.Views.Account +{ + public sealed partial class MergedAccountDetailsPage : MergedAccountDetailsPageAbstract + { + public MergedAccountDetailsPage() + { + InitializeComponent(); + } + } +} diff --git a/Wino.Mail.WinUI/Views/ComposePage.xaml b/Wino.Mail.WinUI/Views/ComposePage.xaml new file mode 100644 index 00000000..9db25cf4 --- /dev/null +++ b/Wino.Mail.WinUI/Views/ComposePage.xaml @@ -0,0 +1,687 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Transparent + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Wino.Mail.WinUI/Views/ComposePage.xaml.cs b/Wino.Mail.WinUI/Views/ComposePage.xaml.cs new file mode 100644 index 00000000..212501d9 --- /dev/null +++ b/Wino.Mail.WinUI/Views/ComposePage.xaml.cs @@ -0,0 +1,702 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Reactive.Linq; +using System.Threading; +using System.Threading.Tasks; +using CommunityToolkit.Mvvm.Messaging; +using EmailValidation; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.UI.Xaml.Controls; +using Microsoft.Web.WebView2.Core; +using MimeKit; +using Windows.ApplicationModel.DataTransfer; +using Windows.Foundation; +using Windows.Storage; +using Windows.Storage.Pickers; +using Windows.UI.ViewManagement.Core; +using Wino.Core.Domain; +using Wino.Core.Domain.Entities; +using Wino.Core.Domain.Enums; +using Wino.Core.Domain.Interfaces; +using Wino.Core.Domain.Models.Reader; +using Wino.Core.Messages.Mails; +using Wino.Core.Messages.Shell; +using Wino.Extensions; +using Wino.Mail.ViewModels.Data; +using Wino.Views.Abstract; +using CommunityToolkit.WinUI.Controls; +using Wino.Helpers; +using System.Text.Json; +using Wino.Mail.WinUI; + + + +#if NET8_0 +using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Media.Animation; +using Microsoft.UI.Xaml.Navigation; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Media.Animation; +using Windows.UI.Xaml.Navigation; +#endif + +namespace Wino.Views +{ + public sealed partial class ComposePage : ComposePageAbstract, + IRecipient, + IRecipient, + IRecipient + { + public bool IsComposerDarkMode + { + get { return (bool)GetValue(IsComposerDarkModeProperty); } + set { SetValue(IsComposerDarkModeProperty, value); } + } + + public static readonly DependencyProperty IsComposerDarkModeProperty = DependencyProperty.Register(nameof(IsComposerDarkMode), typeof(bool), typeof(ComposePage), new PropertyMetadata(false, OnIsComposerDarkModeChanged)); + public WebView2 GetWebView() => Chromium; + + private TaskCompletionSource DOMLoadedTask = new TaskCompletionSource(); + + private List Disposables = new List(); + + public ComposePage() + { + InitializeComponent(); + + Environment.SetEnvironmentVariable("WEBVIEW2_DEFAULT_BACKGROUND_COLOR", "00FFFFFF"); + Environment.SetEnvironmentVariable("WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS", "--enable-features=OverlayScrollbar,msOverlayScrollbarWinStyle,msOverlayScrollbarWinStyleAnimation"); + } + + private static async void OnIsComposerDarkModeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) + { + if (obj is ComposePage page) + { + await page.UpdateEditorThemeAsync(); + } + } + + private IDisposable GetSuggestionBoxDisposable(TokenizingTextBox box) + { + return Observable.FromEventPattern, AutoSuggestBoxTextChangedEventArgs>( + x => box.TextChanged += x, + x => box.TextChanged -= x) + .Throttle(TimeSpan.FromMilliseconds(120)) + .ObserveOn(SynchronizationContext.Current) + .Subscribe(t => + { + if (t.EventArgs.Reason == AutoSuggestionBoxTextChangeReason.UserInput) + { + if (t.Sender is AutoSuggestBox senderBox && senderBox.Text.Length >= 3) + { + _ = ViewModel.ContactService.GetAddressInformationAsync(senderBox.Text).ContinueWith(x => + { + _ = ViewModel.ExecuteUIThread(() => + { + var addresses = x.Result; + + senderBox.ItemsSource = addresses; + }); + }); + } + } + }); + } + + private async void AddFilesClicked(object sender, RoutedEventArgs e) + { + // TODO: Pick files + var picker = new FileOpenPicker() + { + SuggestedStartLocation = PickerLocationId.Desktop + }; + + picker.FileTypeFilter.Add("*"); + var files = await picker.PickMultipleFilesAsync(); + + await AttachFiles(files); + } + + private void OnComposeGridDragOver(object sender, DragEventArgs e) + { + ViewModel.IsDraggingOverComposerGrid = true; + } + + private void OnComposeGridDragLeave(object sender, DragEventArgs e) + { + ViewModel.IsDraggingOverComposerGrid = false; + } + + private void OnFileDropGridDragOver(object sender, DragEventArgs e) + { + ViewModel.IsDraggingOverFilesDropZone = true; + + e.AcceptedOperation = DataPackageOperation.Copy; + e.DragUIOverride.Caption = Translator.ComposerAttachmentsDragDropAttach_Message; + e.DragUIOverride.IsCaptionVisible = true; + e.DragUIOverride.IsGlyphVisible = true; + e.DragUIOverride.IsContentVisible = true; + } + + private void OnFileDropGridDragLeave(object sender, DragEventArgs e) + { + ViewModel.IsDraggingOverFilesDropZone = false; + } + + private async void OnFileDropGridFileDropped(object sender, DragEventArgs e) + { + try + { + if (e.DataView.Contains(StandardDataFormats.StorageItems)) + { + var storageItems = await e.DataView.GetStorageItemsAsync(); + var files = storageItems.OfType(); + + await AttachFiles(files); + } + } + // State should be reset even when an exception occurs, otherwise the UI will be stuck in a dragging state. + finally + { + ViewModel.IsDraggingOverComposerGrid = false; + ViewModel.IsDraggingOverFilesDropZone = false; + } + } + private void OnImageDropGridDragEnter(object sender, DragEventArgs e) + { + bool isValid = false; + if (e.DataView.Contains(StandardDataFormats.StorageItems)) + { + // We can't use async/await here because DragUIOverride becomes inaccessible. + // https://github.com/microsoft/microsoft-ui-xaml/issues/9296 + var files = e.DataView.GetStorageItemsAsync().GetAwaiter().GetResult().OfType(); + + foreach (var file in files) + { + if (ValidateImageFile(file)) + { + isValid = true; + } + } + } + + e.AcceptedOperation = isValid ? DataPackageOperation.Copy : DataPackageOperation.None; + + if (isValid) + { + ViewModel.IsDraggingOverImagesDropZone = true; + e.DragUIOverride.Caption = Translator.ComposerAttachmentsDragDropAttach_Message; + e.DragUIOverride.IsCaptionVisible = true; + e.DragUIOverride.IsGlyphVisible = true; + e.DragUIOverride.IsContentVisible = true; + } + } + + private void OnImageDropGridDragLeave(object sender, DragEventArgs e) + { + ViewModel.IsDraggingOverImagesDropZone = false; + } + + private async void OnImageDropGridImageDropped(object sender, DragEventArgs e) + { + try + { + if (e.DataView.Contains(StandardDataFormats.StorageItems)) + { + var storageItems = await e.DataView.GetStorageItemsAsync(); + var files = storageItems.OfType(); + + var imageDataURLs = new List(); + + foreach (var file in files) + { + if (ValidateImageFile(file)) + imageDataURLs.Add(await GetDataURL(file)); + } + + await InvokeScriptSafeAsync($"insertImages({JsonSerializer.Serialize(imageDataURLs)});"); + } + } + // State should be reset even when an exception occurs, otherwise the UI will be stuck in a dragging state. + finally + { + ViewModel.IsDraggingOverComposerGrid = false; + ViewModel.IsDraggingOverImagesDropZone = false; + } + + static async Task GetDataURL(StorageFile file) + { + return $"data:image/{file.FileType.Replace(".", "")};base64,{Convert.ToBase64String(await file.ReadBytesAsync())}"; + } + } + + private async Task AttachFiles(IEnumerable files) + { + if (files?.Any() != true) return; + + // Convert files to MailAttachmentViewModel. + foreach (var file in files) + { + if (!ViewModel.IncludedAttachments.Any(a => a.FileName == file.Path)) + { + var attachmentViewModel = await file.ToAttachmentViewModelAsync(); + + ViewModel.IncludedAttachments.Add(attachmentViewModel); + } + } + } + + private bool ValidateImageFile(StorageFile file) + { + string[] allowedTypes = new string[] { ".jpg", ".jpeg", ".png" }; + var fileType = file.FileType.ToLower(); + + return allowedTypes.Contains(fileType); + } + + private async void BoldButtonClicked(object sender, RoutedEventArgs e) + { + await InvokeScriptSafeAsync("editor.execCommand('bold')"); + } + + private async void ItalicButtonClicked(object sender, RoutedEventArgs e) + { + await InvokeScriptSafeAsync("editor.execCommand('italic')"); + } + + private async void UnderlineButtonClicked(object sender, RoutedEventArgs e) + { + await InvokeScriptSafeAsync("editor.execCommand('underline')"); + } + + private async void StrokeButtonClicked(object sender, RoutedEventArgs e) + { + await InvokeScriptSafeAsync("editor.execCommand('strikethrough')"); + } + + private async void BulletListButtonClicked(object sender, RoutedEventArgs e) + { + await InvokeScriptSafeAsync("editor.execCommand('insertunorderedlist')"); + } + + private async void OrderedListButtonClicked(object sender, RoutedEventArgs e) + { + await InvokeScriptSafeAsync("editor.execCommand('insertorderedlist')"); + } + + private async void IncreaseIndentClicked(object sender, RoutedEventArgs e) + { + await InvokeScriptSafeAsync("editor.execCommand('indent')"); + } + + private async void DecreaseIndentClicked(object sender, RoutedEventArgs e) + { + await InvokeScriptSafeAsync("editor.execCommand('outdent')"); + } + + private async void AlignmentChanged(object sender, SelectionChangedEventArgs e) + { + var selectedItem = AlignmentListView.SelectedItem as ComboBoxItem; + var alignment = selectedItem.Tag.ToString(); + + switch (alignment) + { + case "left": + await InvokeScriptSafeAsync("editor.execCommand('justifyleft')"); + break; + case "center": + await InvokeScriptSafeAsync("editor.execCommand('justifycenter')"); + break; + case "right": + await InvokeScriptSafeAsync("editor.execCommand('justifyright')"); + break; + case "justify": + await InvokeScriptSafeAsync("editor.execCommand('justifyfull')"); + break; + } + } + + private async void WebViewToggleButtonClicked(object sender, RoutedEventArgs e) + { + var enable = WebviewToolBarButton.IsChecked == true ? "true" : "false"; + await InvokeScriptSafeAsync($"toggleToolbar('{enable}');"); + } + + public async Task ExecuteScriptFunctionAsync(string functionName, params object[] parameters) + { + string script = functionName + "("; + for (int i = 0; i < parameters.Length; i++) + { + script += JsonSerializer.Serialize(parameters[i]); + if (i < parameters.Length - 1) + { + script += ", "; + } + } + script += ");"; + + return await Chromium.ExecuteScriptAsync(script); + } + + private async Task InvokeScriptSafeAsync(string function) + { + if (Chromium == null) return string.Empty; + + try + { + return await Chromium.ExecuteScriptAsync(function); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + + return string.Empty; + } + + private async void AddImageClicked(object sender, RoutedEventArgs e) + { + await InvokeScriptSafeAsync("imageInput.click();"); + } + + private async Task FocusEditorAsync() + { + await InvokeScriptSafeAsync("editor.selection.focus();"); + + Chromium.Focus(FocusState.Keyboard); + Chromium.Focus(FocusState.Programmatic); + } + + private async void EmojiButtonClicked(object sender, RoutedEventArgs e) + { + CoreInputView.GetForCurrentView().TryShow(CoreInputViewKind.Emoji); + + await FocusEditorAsync(); + } + + public async Task UpdateEditorThemeAsync() + { + await DOMLoadedTask.Task; + + if (IsComposerDarkMode) + { + Chromium.CoreWebView2.Profile.PreferredColorScheme = CoreWebView2PreferredColorScheme.Dark; + await InvokeScriptSafeAsync("SetDarkEditor();"); + } + else + { + Chromium.CoreWebView2.Profile.PreferredColorScheme = CoreWebView2PreferredColorScheme.Light; + await InvokeScriptSafeAsync("SetLightEditor();"); + } + } + + private async Task RenderInternalAsync(string htmlBody) + { + await DOMLoadedTask.Task; + + await UpdateEditorThemeAsync(); + + if (string.IsNullOrEmpty(htmlBody)) + { + await ExecuteScriptFunctionAsync("RenderHTML", " "); + } + else + { + await ExecuteScriptFunctionAsync("RenderHTML", htmlBody); + } + } + + protected override void OnNavigatingFrom(NavigatingCancelEventArgs e) + { + base.OnNavigatingFrom(e); + + DisposeDisposables(); + DisposeWebView2(); + } + + private void DisposeWebView2() + { + if (Chromium == null) return; + + Chromium.CoreWebView2Initialized -= ChromiumInitialized; + + if (Chromium.CoreWebView2 != null) + { + Chromium.CoreWebView2.DOMContentLoaded -= DOMLoaded; + Chromium.CoreWebView2.WebMessageReceived -= ScriptMessageReceived; + } + + Chromium.Close(); + GC.Collect(); + } + + private void DisposeDisposables() + { + if (Disposables.Any()) + Disposables.ForEach(a => a.Dispose()); + } + + protected override async void OnNavigatedTo(NavigationEventArgs e) + { + base.OnNavigatedTo(e); + + var anim = ConnectedAnimationService.GetForCurrentView().GetAnimation("WebViewConnectedAnimation"); + anim?.TryStart(Chromium); + + DisposeDisposables(); + + Disposables.Add(GetSuggestionBoxDisposable(ToBox)); + Disposables.Add(GetSuggestionBoxDisposable(CCBox)); + Disposables.Add(GetSuggestionBoxDisposable(BccBox)); + + Chromium.CoreWebView2Initialized -= ChromiumInitialized; + Chromium.CoreWebView2Initialized += ChromiumInitialized; + + await Chromium.EnsureCoreWebView2Async(); + + ViewModel.GetHTMLBodyFunction = new Func>(async () => + { + var editorContent = await InvokeScriptSafeAsync("GetHTMLContent();"); + + return JsonSerializer.Deserialize(editorContent); + }); + + var underlyingThemeService = App.Current.Services.GetService(); + + IsComposerDarkMode = underlyingThemeService.IsUnderlyingThemeDark(); + } + + private async void ChromiumInitialized(Microsoft.UI.Xaml.Controls.WebView2 sender, Microsoft.UI.Xaml.Controls.CoreWebView2InitializedEventArgs args) + { + var editorBundlePath = (await ViewModel.NativeAppService.GetEditorBundlePathAsync()).Replace("editor.html", string.Empty); + + Chromium.CoreWebView2.SetVirtualHostNameToFolderMapping("app.editor", editorBundlePath, CoreWebView2HostResourceAccessKind.Allow); + Chromium.Source = new Uri("https://app.editor/editor.html"); + + Chromium.CoreWebView2.DOMContentLoaded -= DOMLoaded; + Chromium.CoreWebView2.DOMContentLoaded += DOMLoaded; + + Chromium.CoreWebView2.WebMessageReceived -= ScriptMessageReceived; + Chromium.CoreWebView2.WebMessageReceived += ScriptMessageReceived; + } + + private void ScriptMessageReceived(CoreWebView2 sender, CoreWebView2WebMessageReceivedEventArgs args) + { + var change = JsonSerializer.Deserialize(args.WebMessageAsJson); + + if (change.Type == "bold") + { + BoldButton.IsChecked = change.Value == "true"; + } + else if (change.Type == "italic") + { + ItalicButton.IsChecked = change.Value == "true"; + } + else if (change.Type == "underline") + { + UnderlineButton.IsChecked = change.Value == "true"; + } + else if (change.Type == "strikethrough") + { + StrokeButton.IsChecked = change.Value == "true"; + } + else if (change.Type == "ol") + { + OrderedListButton.IsChecked = change.Value == "true"; + } + else if (change.Type == "ul") + { + BulletListButton.IsChecked = change.Value == "true"; + } + else if (change.Type == "indent") + { + IncreaseIndentButton.IsEnabled = change.Value == "disabled" ? false : true; + } + else if (change.Type == "outdent") + { + DecreaseIndentButton.IsEnabled = change.Value == "disabled" ? false : true; + } + else if (change.Type == "alignment") + { + var parsedValue = change.Value switch + { + "jodit-icon_left" => 0, + "jodit-icon_center" => 1, + "jodit-icon_right" => 2, + "jodit-icon_justify" => 3, + _ => 0 + }; + AlignmentListView.SelectionChanged -= AlignmentChanged; + AlignmentListView.SelectedIndex = parsedValue; + AlignmentListView.SelectionChanged += AlignmentChanged; + } + } + + private void DOMLoaded(CoreWebView2 sender, CoreWebView2DOMContentLoadedEventArgs args) => DOMLoadedTask.TrySetResult(true); + + void IRecipient.Receive(NavigationPaneModeChanged message) + { + if (message.NewMode == MenuPaneMode.Hidden) + TopPanelGrid.Padding = new Thickness(48, 6, 6, 6); + else + TopPanelGrid.Padding = new Thickness(16, 6, 6, 6); + } + + async void IRecipient.Receive(CreateNewComposeMailRequested message) + { + await RenderInternalAsync(message.RenderModel.RenderHtml); + } + + private void BarDynamicOverflowChanging(CommandBar sender, DynamicOverflowItemsChangingEventArgs args) + { + if (args.Action == CommandBarDynamicOverflowAction.AddingToOverflow) + sender.OverflowButtonVisibility = CommandBarOverflowButtonVisibility.Visible; + else + sender.OverflowButtonVisibility = CommandBarOverflowButtonVisibility.Collapsed; + } + + private void ShowCCBCCClicked(object sender, RoutedEventArgs e) + { + CCBCCShowButton.Visibility = Visibility.Collapsed; + + CCTextBlock.Visibility = Visibility.Visible; + CCBox.Visibility = Visibility.Visible; + BccTextBlock.Visibility = Visibility.Visible; + BccBox.Visibility = Visibility.Visible; + } + + private async void TokenItemAdding(TokenizingTextBox sender, TokenItemAddingEventArgs args) + { + // Check is valid email. + + if (!EmailValidator.Validate(args.TokenText)) + { + args.Cancel = true; + ViewModel.NotifyInvalidEmail(args.TokenText); + + return; + } + + var deferal = args.GetDeferral(); + + AddressInformation addedItem = null; + + var boxTag = sender.Tag?.ToString(); + + if (boxTag == "ToBox") + addedItem = await ViewModel.GetAddressInformationAsync(args.TokenText, ViewModel.ToItems); + else if (boxTag == "CCBox") + addedItem = await ViewModel.GetAddressInformationAsync(args.TokenText, ViewModel.CCItemsItems); + else if (boxTag == "BCCBox") + addedItem = await ViewModel.GetAddressInformationAsync(args.TokenText, ViewModel.BCCItems); + + if (addedItem == null) + { + args.Cancel = true; + ViewModel.NotifyAddressExists(); + } + else + { + args.Item = addedItem; + } + + deferal.Complete(); + } + + void IRecipient.Receive(ApplicationThemeChanged message) + { + IsComposerDarkMode = message.IsUnderlyingThemeDark; + } + + private void InvertComposerThemeClicked(object sender, RoutedEventArgs e) + { + IsComposerDarkMode = !IsComposerDarkMode; + } + + private void ImportanceClicked(object sender, RoutedEventArgs e) + { + ImportanceFlyout.Hide(); + ImportanceSplitButton.IsChecked = true; + + if (sender is Button senderButton) + { + var selectedImportance = (MessageImportance)senderButton.Tag; + + ViewModel.SelectedMessageImportance = selectedImportance; + (ImportanceSplitButton.Content as SymbolIcon).Symbol = (senderButton.Content as SymbolIcon).Symbol; + } + } + + private void AttachmentClicked(object sender, ItemClickEventArgs e) + { + if (e.ClickedItem is MailAttachmentViewModel attachmentViewModel) + { + ViewModel.RemoveAttachmentCommand.Execute(attachmentViewModel); + } + } + + private async void AddressBoxLostFocus(object sender, RoutedEventArgs e) + { + // Automatically add current text as item if it is valid mail address. + + if (sender is TokenizingTextBox tokenizingTextBox) + { + if (!(tokenizingTextBox.Items.LastOrDefault() is ITokenStringContainer info)) return; + + var currentText = info.Text; + + if (!string.IsNullOrEmpty(currentText) && EmailValidator.Validate(currentText)) + { + var boxTag = tokenizingTextBox.Tag?.ToString(); + + AddressInformation addedItem = null; + ObservableCollection addressCollection = null; + + if (boxTag == "ToBox") + addressCollection = ViewModel.ToItems; + else if (boxTag == "CCBox") + addressCollection = ViewModel.CCItemsItems; + else if (boxTag == "BCCBox") + addressCollection = ViewModel.BCCItems; + + if (addressCollection != null) + addedItem = await ViewModel.GetAddressInformationAsync(currentText, addressCollection); + + // Item has already been added. + if (addedItem == null) + { + tokenizingTextBox.Text = string.Empty; + } + else if (addressCollection != null) + { + addressCollection.Add(addedItem); + tokenizingTextBox.Text = string.Empty; + } + } + } + } + + // Hack: Tokenizing text box losing focus somehow on page Loaded and shifting focus to this element. + // For once we'll switch back to it once CCBBCGotFocus element got focus. + + private bool isInitialFocusHandled = false; + + private void ComposerLoaded(object sender, RoutedEventArgs e) + { + ToBox.Focus(FocusState.Programmatic); + } + + private void CCBBCGotFocus(object sender, RoutedEventArgs e) + { + if (!isInitialFocusHandled) + { + isInitialFocusHandled = true; + ToBox.Focus(FocusState.Programmatic); + } + } + } +} diff --git a/Wino.Mail.WinUI/Views/IdlePage.xaml b/Wino.Mail.WinUI/Views/IdlePage.xaml new file mode 100644 index 00000000..101fdc4d --- /dev/null +++ b/Wino.Mail.WinUI/Views/IdlePage.xaml @@ -0,0 +1,15 @@ + + + + + + diff --git a/Wino.Mail.WinUI/Views/IdlePage.xaml.cs b/Wino.Mail.WinUI/Views/IdlePage.xaml.cs new file mode 100644 index 00000000..dfc0c4f1 --- /dev/null +++ b/Wino.Mail.WinUI/Views/IdlePage.xaml.cs @@ -0,0 +1,12 @@ +using Wino.Views.Abstract; + +namespace Wino.Views +{ + public sealed partial class IdlePage : IdlePageAbstract + { + public IdlePage() + { + InitializeComponent(); + } + } +} diff --git a/Wino.Mail.WinUI/Views/ImapSetup/AdvancedImapSetupPage.xaml b/Wino.Mail.WinUI/Views/ImapSetup/AdvancedImapSetupPage.xaml new file mode 100644 index 00000000..a1b164cc --- /dev/null +++ b/Wino.Mail.WinUI/Views/ImapSetup/AdvancedImapSetupPage.xaml @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +