1
0
mirror of https://github.com/chylex/TweetDuck.git synced 2025-04-18 06:15:49 +02:00

Refactor context menu handling and make adding new types of context easier

This commit is contained in:
chylex 2017-08-27 18:18:30 +02:00
parent 588bb9a093
commit 442d74d0cb
5 changed files with 110 additions and 100 deletions

View File

@ -3,6 +3,7 @@
using System.Windows.Forms; using System.Windows.Forms;
using CefSharp; using CefSharp;
using TweetDuck.Core.Controls; using TweetDuck.Core.Controls;
using TweetDuck.Core.Handling;
using TweetDuck.Core.Notification; using TweetDuck.Core.Notification;
using TweetDuck.Core.Other; using TweetDuck.Core.Other;
using TweetDuck.Core.Utils; using TweetDuck.Core.Utils;
@ -10,8 +11,6 @@
namespace TweetDuck.Core.Bridge{ namespace TweetDuck.Core.Bridge{
sealed class TweetDeckBridge{ sealed class TweetDeckBridge{
public static string LastRightClickedLink = string.Empty;
public static string LastRightClickedImage = string.Empty;
public static string LastHighlightedTweet = string.Empty; public static string LastHighlightedTweet = string.Empty;
public static string LastHighlightedQuotedTweet = string.Empty; public static string LastHighlightedQuotedTweet = string.Empty;
public static string LastHighlightedTweetAuthor = string.Empty; public static string LastHighlightedTweetAuthor = string.Empty;
@ -19,7 +18,7 @@ sealed class TweetDeckBridge{
public static Dictionary<string, string> SessionData = new Dictionary<string, string>(2); public static Dictionary<string, string> SessionData = new Dictionary<string, string>(2);
public static void ResetStaticProperties(){ public static void ResetStaticProperties(){
LastRightClickedLink = LastRightClickedImage = LastHighlightedTweet = LastHighlightedQuotedTweet = LastHighlightedTweetAuthor = string.Empty; LastHighlightedTweet = LastHighlightedQuotedTweet = LastHighlightedTweetAuthor = string.Empty;
LastHighlightedTweetImages = StringUtils.EmptyArray; LastHighlightedTweetImages = StringUtils.EmptyArray;
} }
@ -56,12 +55,8 @@ public void LoadNotificationHeadContents(string headContents){
}); });
} }
public void SetLastRightClickedLink(string link){ public void SetLastRightClickInfo(string type, string link){
form.InvokeAsyncSafe(() => LastRightClickedLink = link); form.InvokeAsyncSafe(() => ContextMenuBase.SetContextInfo(type, link));
}
public void SetLastRightClickedImage(string link){
form.InvokeAsyncSafe(() => LastRightClickedImage = link);
} }
public void SetLastHighlightedTweet(string link, string quotedLink, string author, string imageList){ public void SetLastHighlightedTweet(string link, string quotedLink, string author, string imageList){

View File

@ -6,29 +6,35 @@
using TweetDuck.Core.Bridge; using TweetDuck.Core.Bridge;
using TweetDuck.Core.Controls; using TweetDuck.Core.Controls;
using TweetDuck.Core.Utils; using TweetDuck.Core.Utils;
using System.Collections.Generic;
namespace TweetDuck.Core.Handling{ namespace TweetDuck.Core.Handling{
abstract class ContextMenuBase : IContextMenuHandler{ abstract class ContextMenuBase : IContextMenuHandler{
protected static readonly bool HasDevTools = File.Exists(Path.Combine(Program.ProgramPath, "devtools_resources.pak")); protected static readonly bool HasDevTools = File.Exists(Path.Combine(Program.ProgramPath, "devtools_resources.pak"));
private static TwitterUtils.ImageQuality ImageQuality => Program.UserConfig.TwitterImageQuality; private static TwitterUtils.ImageQuality ImageQuality => Program.UserConfig.TwitterImageQuality;
private static KeyValuePair<string, string> ContextInfo;
private static bool IsLink => ContextInfo.Key == "link";
private static bool IsImage => ContextInfo.Key == "image";
private static bool IsVideo => ContextInfo.Key == "video";
private static string GetLink(IContextMenuParams parameters){ public static void SetContextInfo(string type, string link){
return string.IsNullOrEmpty(TweetDeckBridge.LastRightClickedLink) ? parameters.UnfilteredLinkUrl : TweetDeckBridge.LastRightClickedLink; ContextInfo = new KeyValuePair<string, string>(string.IsNullOrEmpty(link) ? null : type, link);
} }
private static string GetImage(IContextMenuParams parameters){ private static string GetMediaLink(IContextMenuParams parameters){
return string.IsNullOrEmpty(TweetDeckBridge.LastRightClickedImage) ? parameters.SourceUrl : TweetDeckBridge.LastRightClickedImage; return IsImage || IsVideo ? ContextInfo.Value : parameters.SourceUrl;
} }
private const int MenuOpenLinkUrl = 26500; private const CefMenuCommand MenuOpenLinkUrl = (CefMenuCommand)26500;
private const int MenuCopyLinkUrl = 26501; private const CefMenuCommand MenuCopyLinkUrl = (CefMenuCommand)26501;
private const int MenuCopyUsername = 26502; private const CefMenuCommand MenuCopyUsername = (CefMenuCommand)26502;
private const int MenuOpenImageUrl = 26503; private const CefMenuCommand MenuOpenMediaUrl = (CefMenuCommand)26503;
private const int MenuCopyImageUrl = 26504; private const CefMenuCommand MenuCopyMediaUrl = (CefMenuCommand)26504;
private const int MenuSaveImage = 26505; private const CefMenuCommand MenuSaveMedia = (CefMenuCommand)26505;
private const int MenuSaveAllImages = 26506; private const CefMenuCommand MenuSaveTweetImages = (CefMenuCommand)26506;
private const int MenuOpenDevTools = 26599; private const CefMenuCommand MenuOpenDevTools = (CefMenuCommand)26599;
private readonly Form form; private readonly Form form;
@ -40,36 +46,46 @@ protected ContextMenuBase(Form form){
} }
public virtual void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){ public virtual void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
bool hasTweetImage = !string.IsNullOrEmpty(TweetDeckBridge.LastRightClickedImage);
lastHighlightedTweetAuthor = TweetDeckBridge.LastHighlightedTweetAuthor;
lastHighlightedTweetImageList = TweetDeckBridge.LastHighlightedTweetImages;
if (!TwitterUtils.IsTweetDeckWebsite(frame) || browser.IsLoading){ if (!TwitterUtils.IsTweetDeckWebsite(frame) || browser.IsLoading){
lastHighlightedTweetAuthor = string.Empty; lastHighlightedTweetAuthor = string.Empty;
lastHighlightedTweetImageList = StringUtils.EmptyArray; lastHighlightedTweetImageList = StringUtils.EmptyArray;
ContextInfo = default(KeyValuePair<string, string>);
}
else{
lastHighlightedTweetAuthor = TweetDeckBridge.LastHighlightedTweetAuthor;
lastHighlightedTweetImageList = TweetDeckBridge.LastHighlightedTweetImages;
} }
if (parameters.TypeFlags.HasFlag(ContextMenuType.Link) && !parameters.UnfilteredLinkUrl.EndsWith("tweetdeck.twitter.com/#", StringComparison.Ordinal) && !hasTweetImage){ bool hasTweetImage = IsImage;
bool hasTweetVideo = IsVideo;
string TextOpen(string name) => "Open "+name+" in browser";
string TextCopy(string name) => "Copy "+name+" address";
string TextSave(string name) => "Save "+name+" as...";
if (parameters.TypeFlags.HasFlag(ContextMenuType.Link) && !parameters.UnfilteredLinkUrl.EndsWith("tweetdeck.twitter.com/#", StringComparison.Ordinal) && !hasTweetImage && !hasTweetVideo){
if (TwitterUtils.RegexAccount.IsMatch(parameters.UnfilteredLinkUrl)){ if (TwitterUtils.RegexAccount.IsMatch(parameters.UnfilteredLinkUrl)){
model.AddItem((CefMenuCommand)MenuOpenLinkUrl, "Open account in browser"); model.AddItem(MenuOpenLinkUrl, TextOpen("account"));
model.AddItem((CefMenuCommand)MenuCopyLinkUrl, "Copy account address"); model.AddItem(MenuCopyLinkUrl, TextCopy("account"));
model.AddItem((CefMenuCommand)MenuCopyUsername, "Copy account username"); model.AddItem(MenuCopyUsername, "Copy account username");
} }
else{ else{
model.AddItem((CefMenuCommand)MenuOpenLinkUrl, "Open link in browser"); model.AddItem(MenuOpenLinkUrl, TextOpen("link"));
model.AddItem((CefMenuCommand)MenuCopyLinkUrl, "Copy link address"); model.AddItem(MenuCopyLinkUrl, TextCopy("link"));
} }
model.AddSeparator(); model.AddSeparator();
} }
if ((parameters.TypeFlags.HasFlag(ContextMenuType.Media) && parameters.HasImageContents) || hasTweetImage){ if (hasTweetVideo){
model.AddItem((CefMenuCommand)MenuOpenImageUrl, "Open image in browser"); }
model.AddItem((CefMenuCommand)MenuCopyImageUrl, "Copy image address"); else if ((parameters.TypeFlags.HasFlag(ContextMenuType.Media) && parameters.HasImageContents) || hasTweetImage){
model.AddItem((CefMenuCommand)MenuSaveImage, "Save image as..."); model.AddItem(MenuOpenMediaUrl, TextOpen("image"));
model.AddItem(MenuCopyMediaUrl, TextCopy("image"));
model.AddItem(MenuSaveMedia, TextSave("image"));
if (lastHighlightedTweetImageList.Length > 1){ if (lastHighlightedTweetImageList.Length > 1){
model.AddItem((CefMenuCommand)MenuSaveAllImages, "Save all images as..."); model.AddItem(MenuSaveTweetImages, TextSave("all images"));
} }
model.AddSeparator(); model.AddSeparator();
@ -77,35 +93,36 @@ public virtual void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser bro
} }
public virtual bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){ public virtual bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){
switch((int)commandId){ switch(commandId){
case MenuOpenLinkUrl: case MenuOpenLinkUrl:
BrowserUtils.OpenExternalBrowser(parameters.LinkUrl); BrowserUtils.OpenExternalBrowser(parameters.LinkUrl);
break; break;
case MenuCopyLinkUrl: case MenuCopyLinkUrl:
SetClipboardText(GetLink(parameters)); SetClipboardText(IsLink ? ContextInfo.Value : parameters.UnfilteredLinkUrl);
break;
case MenuOpenImageUrl:
BrowserUtils.OpenExternalBrowser(TwitterUtils.GetImageLink(GetImage(parameters), ImageQuality));
break;
case MenuSaveImage:
TwitterUtils.DownloadImage(GetImage(parameters), lastHighlightedTweetAuthor, ImageQuality);
break;
case MenuSaveAllImages:
TwitterUtils.DownloadImages(lastHighlightedTweetImageList, lastHighlightedTweetAuthor, ImageQuality);
break;
case MenuCopyImageUrl:
SetClipboardText(TwitterUtils.GetImageLink(GetImage(parameters), ImageQuality));
break; break;
case MenuCopyUsername: case MenuCopyUsername:
Match match = TwitterUtils.RegexAccount.Match(parameters.UnfilteredLinkUrl); Match match = TwitterUtils.RegexAccount.Match(parameters.UnfilteredLinkUrl);
SetClipboardText(match.Success ? match.Groups[1].Value : parameters.UnfilteredLinkUrl); SetClipboardText(match.Success ? match.Groups[1].Value : parameters.UnfilteredLinkUrl);
break; break;
case MenuOpenMediaUrl:
BrowserUtils.OpenExternalBrowser(TwitterUtils.GetImageLink(GetMediaLink(parameters), ImageQuality));
break;
case MenuCopyMediaUrl:
SetClipboardText(TwitterUtils.GetImageLink(GetMediaLink(parameters), ImageQuality));
break;
case MenuSaveMedia:
TwitterUtils.DownloadImage(GetMediaLink(parameters), lastHighlightedTweetAuthor, ImageQuality);
break;
case MenuSaveTweetImages:
TwitterUtils.DownloadImages(lastHighlightedTweetImageList, lastHighlightedTweetAuthor, ImageQuality);
break;
case MenuOpenDevTools: case MenuOpenDevTools:
browserControl.ShowDevTools(); browserControl.ShowDevTools();
@ -116,8 +133,7 @@ public virtual bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser br
} }
public virtual void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame){ public virtual void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame){
TweetDeckBridge.LastRightClickedLink = string.Empty; ContextInfo = default(KeyValuePair<string, string>);
TweetDeckBridge.LastRightClickedImage = string.Empty;
} }
public virtual bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback){ public virtual bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback){
@ -129,7 +145,7 @@ protected void SetClipboardText(string text){
} }
protected static void AddDebugMenuItems(IMenuModel model){ protected static void AddDebugMenuItems(IMenuModel model){
model.AddItem((CefMenuCommand)MenuOpenDevTools, "Open dev tools"); model.AddItem(MenuOpenDevTools, "Open dev tools");
} }
protected static void RemoveSeparatorIfLast(IMenuModel model){ protected static void RemoveSeparatorIfLast(IMenuModel model){

View File

@ -6,17 +6,17 @@
namespace TweetDuck.Core.Handling{ namespace TweetDuck.Core.Handling{
class ContextMenuBrowser : ContextMenuBase{ class ContextMenuBrowser : ContextMenuBase{
private const int MenuGlobal = 26600; private const CefMenuCommand MenuGlobal = (CefMenuCommand)26600;
private const int MenuMute = 26601; private const CefMenuCommand MenuMute = (CefMenuCommand)26601;
private const int MenuSettings = 26602; private const CefMenuCommand MenuSettings = (CefMenuCommand)26602;
private const int MenuPlugins = 26003; private const CefMenuCommand MenuPlugins = (CefMenuCommand)26003;
private const int MenuAbout = 26604; private const CefMenuCommand MenuAbout = (CefMenuCommand)26604;
private const int MenuOpenTweetUrl = 26610; private const CefMenuCommand MenuOpenTweetUrl = (CefMenuCommand)26610;
private const int MenuCopyTweetUrl = 26611; private const CefMenuCommand MenuCopyTweetUrl = (CefMenuCommand)26611;
private const int MenuOpenQuotedTweetUrl = 26612; private const CefMenuCommand MenuOpenQuotedTweetUrl = (CefMenuCommand)26612;
private const int MenuCopyQuotedTweetUrl = 26613; private const CefMenuCommand MenuCopyQuotedTweetUrl = (CefMenuCommand)26613;
private const int MenuScreenshotTweet = 26614; private const CefMenuCommand MenuScreenshotTweet = (CefMenuCommand)26614;
private const string TitleReloadBrowser = "Reload browser"; private const string TitleReloadBrowser = "Reload browser";
private const string TitleMuteNotifications = "Mute notifications"; private const string TitleMuteNotifications = "Mute notifications";
@ -55,14 +55,14 @@ public override void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser br
} }
if (!string.IsNullOrEmpty(lastHighlightedTweet) && (parameters.TypeFlags & (ContextMenuType.Editable | ContextMenuType.Selection)) == 0){ if (!string.IsNullOrEmpty(lastHighlightedTweet) && (parameters.TypeFlags & (ContextMenuType.Editable | ContextMenuType.Selection)) == 0){
model.AddItem((CefMenuCommand)MenuOpenTweetUrl, "Open tweet in browser"); model.AddItem(MenuOpenTweetUrl, "Open tweet in browser");
model.AddItem((CefMenuCommand)MenuCopyTweetUrl, "Copy tweet address"); model.AddItem(MenuCopyTweetUrl, "Copy tweet address");
model.AddItem((CefMenuCommand)MenuScreenshotTweet, "Screenshot tweet to clipboard"); model.AddItem(MenuScreenshotTweet, "Screenshot tweet to clipboard");
if (!string.IsNullOrEmpty(lastHighlightedQuotedTweet)){ if (!string.IsNullOrEmpty(lastHighlightedQuotedTweet)){
model.AddSeparator(); model.AddSeparator();
model.AddItem((CefMenuCommand)MenuOpenQuotedTweetUrl, "Open quoted tweet in browser"); model.AddItem(MenuOpenQuotedTweetUrl, "Open quoted tweet in browser");
model.AddItem((CefMenuCommand)MenuCopyQuotedTweetUrl, "Copy quoted tweet address"); model.AddItem(MenuCopyQuotedTweetUrl, "Copy quoted tweet address");
} }
model.AddSeparator(); model.AddSeparator();
@ -71,16 +71,16 @@ public override void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser br
if ((parameters.TypeFlags & (ContextMenuType.Editable | ContextMenuType.Selection)) == 0){ if ((parameters.TypeFlags & (ContextMenuType.Editable | ContextMenuType.Selection)) == 0){
AddSeparator(model); AddSeparator(model);
IMenuModel globalMenu = model.Count == 0 ? model : model.AddSubMenu((CefMenuCommand)MenuGlobal, Program.BrandName); IMenuModel globalMenu = model.Count == 0 ? model : model.AddSubMenu(MenuGlobal, Program.BrandName);
globalMenu.AddItem(CefMenuCommand.Reload, TitleReloadBrowser); globalMenu.AddItem(CefMenuCommand.Reload, TitleReloadBrowser);
globalMenu.AddCheckItem((CefMenuCommand)MenuMute, TitleMuteNotifications); globalMenu.AddCheckItem(MenuMute, TitleMuteNotifications);
globalMenu.SetChecked((CefMenuCommand)MenuMute, Program.UserConfig.MuteNotifications); globalMenu.SetChecked(MenuMute, Program.UserConfig.MuteNotifications);
globalMenu.AddSeparator(); globalMenu.AddSeparator();
globalMenu.AddItem((CefMenuCommand)MenuSettings, TitleSettings); globalMenu.AddItem(MenuSettings, TitleSettings);
globalMenu.AddItem((CefMenuCommand)MenuPlugins, TitlePlugins); globalMenu.AddItem(MenuPlugins, TitlePlugins);
globalMenu.AddItem((CefMenuCommand)MenuAbout, TitleAboutProgram); globalMenu.AddItem(MenuAbout, TitleAboutProgram);
if (HasDevTools){ if (HasDevTools){
globalMenu.AddSeparator(); globalMenu.AddSeparator();
@ -96,8 +96,8 @@ public override bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser b
return true; return true;
} }
switch((int)commandId){ switch(commandId){
case (int)CefMenuCommand.Reload: case CefMenuCommand.Reload:
form.InvokeAsyncSafe(form.ReloadToTweetDeck); form.InvokeAsyncSafe(form.ReloadToTweetDeck);
return true; return true;

View File

@ -4,11 +4,11 @@
namespace TweetDuck.Core.Handling{ namespace TweetDuck.Core.Handling{
class ContextMenuNotification : ContextMenuBase{ class ContextMenuNotification : ContextMenuBase{
private const int MenuViewDetail = 26600; private const CefMenuCommand MenuViewDetail = (CefMenuCommand)26600;
private const int MenuSkipTweet = 26601; private const CefMenuCommand MenuSkipTweet = (CefMenuCommand)26601;
private const int MenuFreeze = 26602; private const CefMenuCommand MenuFreeze = (CefMenuCommand)26602;
private const int MenuCopyTweetUrl = 26603; private const CefMenuCommand MenuCopyTweetUrl = (CefMenuCommand)26603;
private const int MenuCopyQuotedTweetUrl = 26604; private const CefMenuCommand MenuCopyQuotedTweetUrl = (CefMenuCommand)26604;
private readonly FormNotificationBase form; private readonly FormNotificationBase form;
private readonly bool enableCustomMenu; private readonly bool enableCustomMenu;
@ -29,17 +29,17 @@ public override void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser br
base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model); base.OnBeforeContextMenu(browserControl, browser, frame, parameters, model);
if (enableCustomMenu){ if (enableCustomMenu){
model.AddItem((CefMenuCommand)MenuViewDetail, "View detail"); model.AddItem(MenuViewDetail, "View detail");
model.AddItem((CefMenuCommand)MenuSkipTweet, "Skip tweet"); model.AddItem(MenuSkipTweet, "Skip tweet");
model.AddCheckItem((CefMenuCommand)MenuFreeze, "Freeze"); model.AddCheckItem(MenuFreeze, "Freeze");
model.SetChecked((CefMenuCommand)MenuFreeze, form.FreezeTimer); model.SetChecked(MenuFreeze, form.FreezeTimer);
model.AddSeparator();
if (!string.IsNullOrEmpty(form.CurrentTweetUrl)){ if (!string.IsNullOrEmpty(form.CurrentTweetUrl)){
model.AddItem((CefMenuCommand)MenuCopyTweetUrl, "Copy tweet address"); model.AddSeparator();
model.AddItem(MenuCopyTweetUrl, "Copy tweet address");
if (!string.IsNullOrEmpty(form.CurrentQuoteUrl)){ if (!string.IsNullOrEmpty(form.CurrentQuoteUrl)){
model.AddItem((CefMenuCommand)MenuCopyQuotedTweetUrl, "Copy quoted tweet address"); model.AddItem(MenuCopyQuotedTweetUrl, "Copy quoted tweet address");
} }
} }
} }
@ -59,7 +59,7 @@ public override bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser b
return true; return true;
} }
switch((int)commandId){ switch(commandId){
case MenuSkipTweet: case MenuSkipTweet:
form.InvokeAsyncSafe(form.FinishCurrentNotification); form.InvokeAsyncSafe(form.FinishCurrentNotification);
return true; return true;

View File

@ -376,17 +376,16 @@
// Block: Allow bypassing of t.co and include media previews in context menus. // Block: Allow bypassing of t.co and include media previews in context menus.
// //
$(document.body).delegate("a", "contextmenu", function(){ $(document.body).delegate("a", "contextmenu", function(){
$TD.setLastRightClickedLink($(this).attr("data-full-url") || "");
});
$(document.body).delegate("a.js-media-image-link", "contextmenu", function(){
let me = $(this)[0]; let me = $(this)[0];
if (me.firstElementChild){ if (me.classList.contains("js-media-image-link") && highlightedTweetObj){
$TD.setLastRightClickedImage(me.firstElementChild.getAttribute("src")); let media = (highlightedTweetObj.quotedTweet || highlightedTweetObj).getMedia().find(media => media.mediaId === me.getAttribute("data-media-entity-id"));
$TD.setLastRightClickInfo("image", media.large());
}
} }
else{ else{
$TD.setLastRightClickedImage(me.style.backgroundImage.replace(/url\(['"]?(.*?)['"]?\)/, "$1")); $TD.setLastRightClickInfo("link", me.getAttribute("data-full-url"));
} }
}); });