Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Peek][PreviewPane] Fix missing Copy menu-item #33845

Merged
merged 7 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 42 additions & 27 deletions src/common/FilePreviewCommon/Assets/Monaco/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
// `theme` can be "vs" for light theme or "vs-dark" for dark theme
// `lang` is the language of the file
// `wrap` if the editor is wrapping or not

var theme = ("[[PT_THEME]]" == "dark") ? "vs-dark" : "vs";
var lang = "[[PT_LANG]]";
var wrap = ([[PT_WRAP]] == 1) ? true : false;
Expand All @@ -19,11 +19,29 @@
var stickyScroll = ([[PT_STICKY_SCROLL]] == 1) ? true : false;

var fontSize = [[PT_FONT_SIZE]];

var contextMenu = ([[PT_CONTEXTMENU]] == 1) ? true : false;

var editor;

// Code taken from https://stackoverflow.com/a/30106551/14774889
var code = decodeURIComponent(atob(base64code).split('').map(function(c) {
var code = decodeURIComponent(atob(base64code).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));

function runToggleTextWrapCommand() {
if (wrap) {
editor.updateOptions({ wordWrap: 'off' })
} else {
editor.updateOptions({ wordWrap: 'on' })
}
wrap = !wrap;
}

function runCopyCommand() {
editor.focus();
document.execCommand('copy');
}

</script>
<!-- Set browser to Edge-->
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
Expand All @@ -33,32 +51,33 @@
<title>Previewer for developer Files</title>
<style>
/* Fits content to window size */
html, body{
padding:0;
html, body {
padding: 0;
}
#container,.monaco-editor {
position:fixed;
height:100%;
left:0;
top:0;
right:0;
bottom:0;

#container, .monaco-editor {
position: fixed;
height: 100%;
left: 0;
top: 0;
right: 0;
bottom: 0;
}
.overflowingContentWidgets{

.overflowingContentWidgets {
/*Hides alert box */
display:none!important
}
display: none !important
}
</style>
</head>

<body oncontextmenu="onContextMenu()">
<body>
<!-- Container for the editor -->
<div id="container"></div>
<!-- Script -->
<script src="http://[[PT_URL]]/monacoSRC/min/vs/loader.js"></script>
<script src="http://[[PT_URL]]/monacoSpecialLanguages.js" type="module"></script>
<script type="module">
var editor;
<script type="module">
import { registerAdditionalLanguages } from 'http://[[PT_URL]]/monacoSpecialLanguages.js';
import { customTokenColors } from 'http://[[PT_URL]]/customTokenColors.js';
require.config({ paths: { vs: 'http://[[PT_URL]]/monacoSRC/min/vs' } });
Expand All @@ -80,8 +99,9 @@
language: lang, // Sets language of the code
readOnly: true, // Sets to readonly
theme: 'theme', // Sets editor theme
minimap: {enabled: false}, // Disables minimap
minimap: { enabled: false }, // Disables minimap
lineNumbersMinChars: '3', // Width of the line numbers
contextmenu: contextMenu,
scrollbar: {
// Deactivate shadows
shadows: false,
Expand All @@ -90,7 +110,7 @@
vertical: 'auto',
horizontal: 'auto',
},
stickyScroll: {enabled: stickyScroll},
stickyScroll: { enabled: stickyScroll },
fontSize: fontSize,
wordWrap: (wrap ? 'on' : 'off') // Word wraps
});
Expand All @@ -117,12 +137,7 @@
// Method that will be executed when the action is triggered.
// @param editor The editor instance is passed in as a convenience
run: function (ed) {
if (wrap) {
editor.updateOptions({ wordWrap: 'off' })
} else {
editor.updateOptions({ wordWrap: 'on' })
}
wrap = !wrap;
runToggleTextWrapCommand();
}
});

Expand Down Expand Up @@ -151,4 +166,4 @@
}
</script>
</body>
</html>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ManagedCommon;
using Microsoft.UI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.Web.WebView2.Core;
using Peek.Common.Constants;
using Peek.Common.Helpers;
using Windows.ApplicationModel.DataTransfer;
using Windows.System;
using Windows.UI;
Expand Down Expand Up @@ -67,6 +70,25 @@ public bool IsDevFilePreview
}
}

public static readonly DependencyProperty CustomContextMenuProperty = DependencyProperty.Register(
nameof(CustomContextMenu),
typeof(bool),
typeof(BrowserControl),
null);

public bool CustomContextMenu
{
get
{
return (bool)GetValue(CustomContextMenuProperty);
}

set
{
SetValue(CustomContextMenuProperty, value);
}
}

public BrowserControl()
{
this.InitializeComponent();
Expand All @@ -78,6 +100,7 @@ public void Dispose()
if (PreviewBrowser.CoreWebView2 != null)
{
PreviewBrowser.CoreWebView2.DOMContentLoaded -= CoreWebView2_DOMContentLoaded;
PreviewBrowser.CoreWebView2.ContextMenuRequested -= CoreWebView2_ContextMenuRequested;
}
}

Expand Down Expand Up @@ -145,7 +168,7 @@ private async void PreviewWV2_Loaded(object sender, RoutedEventArgs e)
PreviewBrowser.DefaultBackgroundColor = Color.FromArgb(0, 0, 0, 0);

PreviewBrowser.CoreWebView2.Settings.AreDefaultScriptDialogsEnabled = false;
PreviewBrowser.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false;
PreviewBrowser.CoreWebView2.Settings.AreDefaultContextMenusEnabled = true;
PreviewBrowser.CoreWebView2.Settings.AreDevToolsEnabled = false;
PreviewBrowser.CoreWebView2.Settings.AreHostObjectsAllowed = false;
PreviewBrowser.CoreWebView2.Settings.IsGeneralAutofillEnabled = false;
Expand All @@ -164,6 +187,7 @@ private async void PreviewWV2_Loaded(object sender, RoutedEventArgs e)

PreviewBrowser.CoreWebView2.DOMContentLoaded += CoreWebView2_DOMContentLoaded;
PreviewBrowser.CoreWebView2.NewWindowRequested += CoreWebView2_NewWindowRequested;
PreviewBrowser.CoreWebView2.ContextMenuRequested += CoreWebView2_ContextMenuRequested;
}
catch (Exception ex)
{
Expand All @@ -173,6 +197,47 @@ private async void PreviewWV2_Loaded(object sender, RoutedEventArgs e)
Navigate();
}

private void CoreWebView2_ContextMenuRequested(CoreWebView2 sender, CoreWebView2ContextMenuRequestedEventArgs args)
{
var menuItems = args.MenuItems;

if (menuItems.IsReadOnly)
{
return;
}

CoreWebView2ContextMenuItem CreateCommandMenuItem(string resourceId, string commandName)
{
var label = ResourceLoaderInstance.ResourceLoader.GetString(resourceId);
var commandMenuItem = sender.Environment.CreateContextMenuItem(label, null, CoreWebView2ContextMenuItemKind.Command);
commandMenuItem.CustomItemSelected += async (_, _) =>
{
await sender.ExecuteScriptAsync($"{commandName}()");
};
return commandMenuItem;
}

// When using Monaco, we show menu items that call the appropriate JS functions -
// WebView2 isn't able to show a "Copy" menu item of its own.
// When not using Monaco, we keep the "Copy" menu item from WebView2's default context menu.
List<CoreWebView2ContextMenuItem> GetMenuItemsToShow() =>
CustomContextMenu
? [
CreateCommandMenuItem("ContextMenu_Copy", "runCopyCommand"),
sender.Environment.CreateContextMenuItem(string.Empty, null, CoreWebView2ContextMenuItemKind.Separator),
CreateCommandMenuItem("ContextMenu_ToggleTextWrapping", "runToggleTextWrapCommand"),
]
: menuItems.Where(menuItem => menuItem.Name == "copy").ToList();

var menuItemsToShow = GetMenuItemsToShow();

menuItems.Clear();
foreach (var menuItemToShow in menuItemsToShow)
{
menuItems.Add(menuItemToShow);
}
}

private void CoreWebView2_DOMContentLoaded(CoreWebView2 sender, CoreWebView2DOMContentLoadedEventArgs args)
{
// If the file being previewed is HTML or HTM, reset the background color to its original state.
Expand Down Expand Up @@ -202,7 +267,7 @@ private async void CoreWebView2_NewWindowRequested(CoreWebView2 sender, CoreWebV
}
}

private async void PreviewBrowser_NavigationStarting(WebView2 sender, Microsoft.Web.WebView2.Core.CoreWebView2NavigationStartingEventArgs args)
private async void PreviewBrowser_NavigationStarting(WebView2 sender, CoreWebView2NavigationStartingEventArgs args)
{
if (_navigatedUri == null)
{
Expand All @@ -218,7 +283,7 @@ private async void PreviewBrowser_NavigationStarting(WebView2 sender, Microsoft.
}
}

private void PreviewWV2_NavigationCompleted(WebView2 sender, Microsoft.Web.WebView2.Core.CoreWebView2NavigationCompletedEventArgs args)
private void PreviewWV2_NavigationCompleted(WebView2 sender, CoreWebView2NavigationCompletedEventArgs args)
{
if (args.IsSuccess)
{
Expand Down
1 change: 1 addition & 0 deletions src/modules/peek/Peek.FilePreviewer/FilePreview.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
<controls:BrowserControl
x:Name="BrowserPreview"
x:Load="True"
CustomContextMenu="{x:Bind BrowserPreviewer.CustomContextMenu, Mode=OneWay}"
DOMContentLoaded="BrowserPreview_DOMContentLoaded"
FlowDirection="LeftToRight"
IsDevFilePreview="{x:Bind BrowserPreviewer.IsDevFilePreview, Mode=OneWay}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@ public interface IBrowserPreviewer : IPreviewer, IPreviewTarget
public Uri? Preview { get; }

public bool IsDevFilePreview { get; }

public bool CustomContextMenu { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ private static string InitializeIndexFileAndSelectedFile(string fileContent, str

html = html.Replace("[[PT_LANG]]", vsCodeLangSet, StringComparison.InvariantCulture);
html = html.Replace("[[PT_WRAP]]", wrapText ? "1" : "0", StringComparison.InvariantCulture);
html = html.Replace("[[PT_CONTEXTMENU]]", "0", StringComparison.InvariantCulture);
html = html.Replace("[[PT_STICKY_SCROLL]]", stickyScroll ? "1" : "0", StringComparison.InvariantCulture);
html = html.Replace("[[PT_THEME]]", theme, StringComparison.InvariantCulture);
html = html.Replace("[[PT_FONT_SIZE]]", fontSize.ToString(CultureInfo.InvariantCulture), StringComparison.InvariantCulture);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ public partial class WebBrowserPreviewer : ObservableObject, IBrowserPreviewer,
[ObservableProperty]
private bool isDevFilePreview;

[ObservableProperty]
private bool customContextMenu;

private bool disposed;

public WebBrowserPreviewer(IFileSystemItem file, IPreviewSettings previewSettings)
Expand Down Expand Up @@ -107,9 +110,14 @@ await Dispatcher.RunOnUiThread(async () =>
{
bool isHtml = File.Extension == ".html" || File.Extension == ".htm";
bool isMarkdown = File.Extension == ".md";
IsDevFilePreview = MonacoHelper.SupportedMonacoFileTypes.Contains(File.Extension);

if (IsDevFilePreview && !isHtml && !isMarkdown)
bool supportedByMonaco = MonacoHelper.SupportedMonacoFileTypes.Contains(File.Extension);
bool useMonaco = supportedByMonaco && !isHtml && !isMarkdown;

IsDevFilePreview = supportedByMonaco;
CustomContextMenu = useMonaco;

if (useMonaco)
{
var raw = await ReadHelper.Read(File.Path.ToString());
Preview = new Uri(MonacoHelper.PreviewTempFile(raw, File.Extension, TempFolderPath.Path, _previewSettings.SourceCodeTryFormat, _previewSettings.SourceCodeWrapText, _previewSettings.SourceCodeStickyScroll, _previewSettings.SourceCodeFontSize));
Expand Down
8 changes: 8 additions & 0 deletions src/modules/peek/Peek.UI/Strings/en-us/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -318,4 +318,12 @@
<value>Length: {0}</value>
<comment>{0} is the duration of the audio read from file metadata</comment>
</data>
<data name="ContextMenu_Copy" xml:space="preserve">
<value>Copy</value>
<comment>Copy selected text to clipboard</comment>
</data>
<data name="ContextMenu_ToggleTextWrapping" xml:space="preserve">
<value>Toggle text wrapping</value>
<comment>Toggle whether text in pane is word-wrapped</comment>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ public override void DoPreview<T>(T dataSource)
await _browser.EnsureCoreWebView2Async(_webView2Environment).ConfigureAwait(true);
_browser.CoreWebView2.SetVirtualHostNameToFolderMapping(VirtualHostName, AssemblyDirectory, CoreWebView2HostResourceAccessKind.Deny);
_browser.CoreWebView2.Settings.AreDefaultScriptDialogsEnabled = false;
_browser.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false;
_browser.CoreWebView2.Settings.AreDefaultContextMenusEnabled = true;
_browser.CoreWebView2.Settings.AreDevToolsEnabled = false;
_browser.CoreWebView2.Settings.AreHostObjectsAllowed = false;
_browser.CoreWebView2.Settings.IsGeneralAutofillEnabled = false;
Expand All @@ -162,6 +162,23 @@ public override void DoPreview<T>(T dataSource)
}
};

_browser.CoreWebView2.ContextMenuRequested += (object sender, CoreWebView2ContextMenuRequestedEventArgs args) =>
{
var menuItems = args.MenuItems;

if (!menuItems.IsReadOnly)
{
var copyMenuItem = menuItems.FirstOrDefault(menuItem => menuItem.Name == "copy");

menuItems.Clear();

if (copyMenuItem != null)
{
menuItems.Add(copyMenuItem);
}
}
};

// WebView2.NavigateToString() limitation
// See https://learn.microsoft.com/dotnet/api/microsoft.web.webview2.core.corewebview2.navigatetostring?view=webview2-dotnet-1.0.864.35#remarks
// While testing the limit, it turned out it is ~1.5MB, so to be on a safe side we go for 1.5m bytes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ private void InitializeIndexFileAndSelectedFile(string filePath)
_html = FilePreviewCommon.MonacoHelper.ReadIndexHtml();
_html = _html.Replace("[[PT_LANG]]", _vsCodeLangSet, StringComparison.InvariantCulture);
_html = _html.Replace("[[PT_WRAP]]", _settings.Wrap ? "1" : "0", StringComparison.InvariantCulture);
_html = _html.Replace("[[PT_CONTEXTMENU]]", "1", StringComparison.InvariantCulture);
_html = _html.Replace("[[PT_THEME]]", Settings.GetTheme(), StringComparison.InvariantCulture);
_html = _html.Replace("[[PT_STICKY_SCROLL]]", _settings.StickyScroll ? "1" : "0", StringComparison.InvariantCulture);
_html = _html.Replace("[[PT_FONT_SIZE]]", _settings.FontSize.ToString(CultureInfo.InvariantCulture), StringComparison.InvariantCulture);
Expand Down
Loading