using CefSharp; using System; using System.IO; using System.Text.RegularExpressions; using System.Windows.Forms; using TweetDuck.Core.Bridge; using TweetDuck.Core.Controls; using TweetDuck.Core.Utils; namespace TweetDuck.Core.Handling{ abstract class ContextMenuBase : IContextMenuHandler{ private static readonly Lazy<Regex> RegexTwitterAccount = new Lazy<Regex>(() => new Regex(@"^https?://twitter\.com/([^/]+)/?$", RegexOptions.Compiled), false); protected static readonly bool HasDevTools = File.Exists(Path.Combine(Program.ProgramPath, "devtools_resources.pak")); private static TwitterUtils.ImageQuality ImageQuality => Program.UserConfig.TwitterImageQuality; private static string GetLink(IContextMenuParams parameters){ return string.IsNullOrEmpty(TweetDeckBridge.LastRightClickedLink) ? parameters.UnfilteredLinkUrl : TweetDeckBridge.LastRightClickedLink; } private static string GetImage(IContextMenuParams parameters){ return string.IsNullOrEmpty(TweetDeckBridge.LastRightClickedImage) ? parameters.SourceUrl : TweetDeckBridge.LastRightClickedImage; } private const int MenuOpenLinkUrl = 26500; private const int MenuCopyLinkUrl = 26501; private const int MenuCopyUsername = 26502; private const int MenuOpenImageUrl = 26503; private const int MenuCopyImageUrl = 26504; private const int MenuSaveImage = 26505; private const int MenuSaveAllImages = 26506; private const int MenuOpenDevTools = 26599; private readonly Form form; private string[] lastHighlightedTweetImageList; protected ContextMenuBase(Form form){ this.form = form; } public virtual void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){ bool hasTweetImage = !string.IsNullOrEmpty(TweetDeckBridge.LastRightClickedImage); lastHighlightedTweetImageList = TweetDeckBridge.LastHighlightedTweetImages; if (!TwitterUtils.IsTweetDeckWebsite(frame) || browser.IsLoading){ lastHighlightedTweetImageList = StringUtils.EmptyArray; } if (parameters.TypeFlags.HasFlag(ContextMenuType.Link) && !parameters.UnfilteredLinkUrl.EndsWith("tweetdeck.twitter.com/#", StringComparison.Ordinal) && !hasTweetImage){ if (RegexTwitterAccount.Value.IsMatch(parameters.UnfilteredLinkUrl)){ model.AddItem((CefMenuCommand)MenuOpenLinkUrl, "Open account in browser"); model.AddItem((CefMenuCommand)MenuCopyLinkUrl, "Copy account address"); model.AddItem((CefMenuCommand)MenuCopyUsername, "Copy account username"); } else{ model.AddItem((CefMenuCommand)MenuOpenLinkUrl, "Open link in browser"); model.AddItem((CefMenuCommand)MenuCopyLinkUrl, "Copy link address"); } model.AddSeparator(); } if ((parameters.TypeFlags.HasFlag(ContextMenuType.Media) && parameters.HasImageContents) || hasTweetImage){ model.AddItem((CefMenuCommand)MenuOpenImageUrl, "Open image in browser"); model.AddItem((CefMenuCommand)MenuCopyImageUrl, "Copy image address"); model.AddItem((CefMenuCommand)MenuSaveImage, "Save image as..."); if (lastHighlightedTweetImageList.Length > 1){ model.AddItem((CefMenuCommand)MenuSaveAllImages, "Save all images as..."); } model.AddSeparator(); } } public virtual bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){ switch((int)commandId){ case MenuOpenLinkUrl: BrowserUtils.OpenExternalBrowser(parameters.LinkUrl); break; case MenuCopyLinkUrl: SetClipboardText(GetLink(parameters)); break; case MenuOpenImageUrl: BrowserUtils.OpenExternalBrowser(TwitterUtils.GetImageLink(GetImage(parameters), ImageQuality)); break; case MenuSaveImage: TwitterUtils.DownloadImage(GetImage(parameters), ImageQuality); break; case MenuSaveAllImages: TwitterUtils.DownloadImages(lastHighlightedTweetImageList, ImageQuality); break; case MenuCopyImageUrl: SetClipboardText(TwitterUtils.GetImageLink(GetImage(parameters), ImageQuality)); break; case MenuCopyUsername: Match match = RegexTwitterAccount.Value.Match(parameters.UnfilteredLinkUrl); SetClipboardText(match.Success ? match.Groups[1].Value : parameters.UnfilteredLinkUrl); break; case MenuOpenDevTools: browserControl.ShowDevTools(); break; } return false; } public virtual void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame){ TweetDeckBridge.LastRightClickedLink = string.Empty; TweetDeckBridge.LastRightClickedImage = string.Empty; } public virtual bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback){ return false; } protected void SetClipboardText(string text){ form.InvokeAsyncSafe(() => WindowsUtils.SetClipboard(text, TextDataFormat.UnicodeText)); } protected static void AddDebugMenuItems(IMenuModel model){ model.AddItem((CefMenuCommand)MenuOpenDevTools, "Open dev tools"); } protected static void RemoveSeparatorIfLast(IMenuModel model){ if (model.Count > 0 && model.GetTypeAt(model.Count-1) == MenuItemType.Separator){ model.RemoveAt(model.Count-1); } } protected static void AddSeparator(IMenuModel model){ if (model.Count > 0 && model.GetTypeAt(model.Count-1) != MenuItemType.Separator){ // do not add separators if there is nothing to separate model.AddSeparator(); } } } }