From aebe82e3a7145fd13352a2fdeeaa8572e57327fb Mon Sep 17 00:00:00 2001
From: chylex <contact@chylex.com>
Date: Fri, 21 Jul 2017 10:46:28 +0200
Subject: [PATCH] Add context menu for image previews that use background-image

---
 Core/Bridge/TweetDeckBridge.cs   |  7 ++++++-
 Core/Handling/ContextMenuBase.cs | 27 ++++++++++++++++++++-------
 Resources/Scripts/code.js        |  6 +++++-
 3 files changed, 31 insertions(+), 9 deletions(-)

diff --git a/Core/Bridge/TweetDeckBridge.cs b/Core/Bridge/TweetDeckBridge.cs
index dca05a77..13cd422d 100644
--- a/Core/Bridge/TweetDeckBridge.cs
+++ b/Core/Bridge/TweetDeckBridge.cs
@@ -7,11 +7,12 @@
 namespace TweetDuck.Core.Bridge{
     sealed class TweetDeckBridge{
         public static string LastRightClickedLink = string.Empty;
+        public static string LastRightClickedImage = string.Empty;
         public static string LastHighlightedTweet = string.Empty;
         public static string LastHighlightedQuotedTweet = string.Empty;
 
         public static void ResetStaticProperties(){
-            LastRightClickedLink = LastHighlightedTweet = LastHighlightedQuotedTweet = string.Empty;
+            LastRightClickedLink = LastRightClickedImage = LastHighlightedTweet = LastHighlightedQuotedTweet = string.Empty;
         }
 
         private readonly FormBrowser form;
@@ -38,6 +39,10 @@ public void SetLastRightClickedLink(string link){
             form.InvokeAsyncSafe(() => LastRightClickedLink = link);
         }
 
+        public void SetLastRightClickedImage(string link){
+            form.InvokeAsyncSafe(() => LastRightClickedImage = link);
+        }
+
         public void SetLastHighlightedTweet(string link, string quotedLink){
             form.InvokeAsyncSafe(() => {
                 LastHighlightedTweet = link;
diff --git a/Core/Handling/ContextMenuBase.cs b/Core/Handling/ContextMenuBase.cs
index 64d7d699..aa174b36 100644
--- a/Core/Handling/ContextMenuBase.cs
+++ b/Core/Handling/ContextMenuBase.cs
@@ -14,6 +14,14 @@ abstract class ContextMenuBase : IContextMenuHandler{
 
         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;
@@ -29,7 +37,9 @@ protected ContextMenuBase(Form form){
         }
 
         public virtual void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){
-            if (parameters.TypeFlags.HasFlag(ContextMenuType.Link) && !parameters.UnfilteredLinkUrl.EndsWith("tweetdeck.twitter.com/#", StringComparison.Ordinal)){
+            bool hasTweetImage = !string.IsNullOrEmpty(TweetDeckBridge.LastRightClickedImage);
+
+            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");
@@ -43,7 +53,7 @@ public virtual void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser bro
                 model.AddSeparator();
             }
 
-            if (parameters.TypeFlags.HasFlag(ContextMenuType.Media) && parameters.HasImageContents){
+            if ((parameters.TypeFlags.HasFlag(ContextMenuType.Media) && parameters.HasImageContents) || hasTweetImage){
                 model.AddItem((CefMenuCommand)MenuOpenImage, "Open image in browser");
                 model.AddItem((CefMenuCommand)MenuSaveImage, "Save image as...");
                 model.AddItem((CefMenuCommand)MenuCopyImageUrl, "Copy image address");
@@ -58,19 +68,19 @@ public virtual bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser br
                     break;
 
                 case MenuCopyLinkUrl:
-                    SetClipboardText(string.IsNullOrEmpty(TweetDeckBridge.LastRightClickedLink) ? parameters.UnfilteredLinkUrl : TweetDeckBridge.LastRightClickedLink);
+                    SetClipboardText(GetLink(parameters));
                     break;
 
                 case MenuOpenImage:
-                    BrowserUtils.OpenExternalBrowser(TwitterUtils.GetImageLink(parameters.SourceUrl, ImageQuality));
+                    BrowserUtils.OpenExternalBrowser(TwitterUtils.GetImageLink(GetImage(parameters), ImageQuality));
                     break;
 
                 case MenuSaveImage:
-                    TwitterUtils.DownloadImage(parameters.SourceUrl, ImageQuality);
+                    TwitterUtils.DownloadImage(GetImage(parameters), ImageQuality);
                     break;
 
                 case MenuCopyImageUrl:
-                    SetClipboardText(TwitterUtils.GetImageLink(parameters.SourceUrl, ImageQuality));
+                    SetClipboardText(TwitterUtils.GetImageLink(GetImage(parameters), ImageQuality));
                     break;
 
                 case MenuCopyUsername:
@@ -86,7 +96,10 @@ public virtual bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser br
             return false;
         }
 
-        public virtual void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame){}
+        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;
diff --git a/Resources/Scripts/code.js b/Resources/Scripts/code.js
index 15aee67f..417d6bb4 100644
--- a/Resources/Scripts/code.js
+++ b/Resources/Scripts/code.js
@@ -323,12 +323,16 @@
   })();
   
   //
-  // Block: Allow bypassing of t.co in context menus.
+  // Block: Allow bypassing of t.co and include media previews in context menus.
   //
   $(document.body).delegate("a", "contextmenu", function(){
     $TD.setLastRightClickedLink($(this).attr("data-full-url") || "");
   });
   
+  $(document.body).delegate("a.js-media-image-link", "contextmenu", function(){
+    $TD.setLastRightClickedImage($(this)[0].style.backgroundImage.replace(/url\(['"]?(.*?)['"]?\)/, "$1"));
+  });
+  
   //
   // Block: Hook into the notification sound effect.
   //