How to display Find dialog in a WebView2 control? - javascript

I have got an old C++ MFC app upgraded to use the WebView2 web browser control, based on Edge. Otherwise I have got it working fine, one of the remaining issues is opening the Find dialog in it via the main MFC app Edit-Find menu item or via Ctrl+F (which is also intercepted by MFC framework). What I have now is:
m_webView->ExecuteScript(L"window.find(\"\", 0, 0, 0, 0, 0, 1);");
where m_webView is a pointer to ICoreWebView2 interface.
The problem is that sometimes it does bring up the Find dialog, sometimes not. Sometimes it does it after page refresh, sometimes not. When I close the Find dialog from cross, it typically refuses to open it again.
How can I make it behave properly? Maybe there is a way which does not need to go through Javascript?
Update: it appears it only worked if the Ctrl+F keystroke was somehow sent directly to the WebView2 control, bypassing MFC. It looks like the above Javascript line never worked. So maybe there is a way to simulate Ctrl+F for the WebView2 control?

AFAIK, WebView2 currently has no support for you invoking or otherwise controlling the find in page dialog. You can also refer to this thread. There is a similar thread in GitHub and the official hasn't given a solution.
You can use Ctrl+F keystroke directly in WebView2 control or provide feedback about this issue on WebView2 Feedback page. Thanks for your understanding.

As #yu-zhou answered, there is no official way yet to do what I wanted. For now I resorted back for emulating Ctrl+F programmatically for the WebView2 control, but the result ain't so pretty. For the record I still present it here:
First, the user has to click in the webview2 control at least once, so I can record its HWND in the GotFocus event handler registered by add_GotFocus():
void MyHtmlView::OnGotFocus() {
if (!m_webview2_hwnd) {
m_webview2_hwnd = ::GetFocus();
}
}
Now, when I want to bring up the Find bar programmatically, I need to ensure the correct window is focused and send it the Ctrl+F key. Alas, it appears the control checks the Ctrl key state in async way, so it gets a bit tricky, I need to alter the keyboard state for the thread and add an extra event handler for restoring it afterwards. After some trial and error I reached this (error checks omitted for brevity):
void MyHtmlView::Find() {
if (::GetFocus()!=m_webview2_hwnd) {
::SetFocus(m_webview2_hwnd);
}
std::uint8_t state[256];
::GetKeyboardState(state);
bool restoreCtrlState = false;
if ((state[VK_CONTROL] & 0x80)==0) {
// Ctrl key is currently not pressed.
// Mark it pressed.
state[VK_CONTROL] |= 0x80;
::SetKeyboardState(state);
restoreCtrlState = true;
}
std::thread auxThread([this, restoreCtrlState]() {
::SendMessage(m_webview2_hwnd, WM_KEYDOWN, 'F', 1);
::SendMessage(m_webview2_hwnd, WM_KEYUP, 'F', 1);
if (restoreCtrlState) {
::PostMessage(m_hWnd, WM_COMMAND, ID_RESTORE_CONTROL_STATE, 0);
}
});
auxThread.detach();
}
// This needs to be registered to handle ID_RESTORE_CONTROL_STATE
void HtmlView::OnRestoreCtrlState() {
std::uint8_t state[256];
::GetKeyboardState(state);
if ((state[VK_CONTROL] & 0x80)!=0) {
state[VK_CONTROL] &= ~0x80;
::SetKeyboardState(state);
}
}
Needless to say, this hack may easily cease to work if they change something in the webview2 implementation.

Related

a11y & angularjs - windows screen reader overrides keydown event

im working on making a photo gallery app more accessible.
the app has a feature of showing expanded view of an image when clicked.
one of the a11y requirements is that when a user focus an image and click enter the expand mode will open and the focus will go inside the expanded view, and will be set on one of the buttons in it. it work's fine without screen reader, or with screen reader on mac. but on windows
when using screen reader it seems that the code that fires is the one that subscribed to the click event and not the keydown event. because the flag that suppose to be set to true on keydown is false (both events fire the same function but the keydown also add the enterClicked variable set to true).
this is the div that hold the image and subscribed to the events:
<div
tabindex="0"
id="{{media.id}}"
data-ng-repeat="media in row track by media.id"
data-ng-mouseenter="events.toggleVideoPlay(media.type, media.id, media.link, ( rowNummer ) * (row.length) + ($index + 1))" class="imgContainer"
ng-keydown="$event.keyCode == 13 ? events.openExpandMode(media.id, true) : null"
data-ng-click="events.openExpandMode(media.id)"
>
openExpandMode function:
$scope.events.openExpandMode = (mediaId, isEnterClicked) => {
const state = {
isEnterClicked,
mediasId,
currentIndex,
pagination: $scope.mediasPagination,
settings: {
isUserName: $scope.settings.user_name_checkbox,
isTemplate: !$scope.userConnected && !$scope.userConnectedWithOldApi,
isLikeComments: $scope.settings.like_comments_checkbox,
isDescriptions: $scope.settings.description_checkbox,
isComments: $scope.settings.comments_checkbox,
theme: $scope.settings.expand_theme,
lang: $translate.use()
}
};
localStorageService.set('state', state);
}
expand mode component init:
const _init = () => {
if ($scope.isOpenFromEnter) {
document.getElementById('nextArrow').setAttribute('data-focus-visible-added', "");
document.getElementById('nextArrow').className += ' focus-visible';
document.getElementById('nextArrow').focus();
}
}
is there a way to stop windows screen reader event interception ?
Short answer
It's common to send a click event instead of a press enter event.
The best is probably to adapt your code so that click and enter do the same thing, and that either or both event can be sent, because
you only have a quite limited influence on which is sent or not and when
Longer answer
You haven't indicated which screen reader you were using (Jaws or NVDA), but anyway, it's common for both to send a click event when pressing enter, instead of sending key events.
Reasons for that may seem strange and illogical at first, but there are at least two good ones:
It's certainly as much illogical to have two different things happening when clicking or pressing enter. IN all applications since GUI exist, most often, both do the same action (the only exception I can think of right now is multiline or rich text fields).
Scren readers existed before web accessibility, and accessibility is still rarely implemented nowadays. Sending a click event when pressing enter provide a minimal usability in all the places where designers didn't even thought that the keyboard could be used instead of the mouse.
By the way, screen reader or not, guess which event is sent if you press enter when the focus is on a link or a button?
Depending on the browser, the answer isn't unanimous as far as I know.
And on the screen reader side, it isn't unanimous either. Some even allow to configure the exact behavior to take, in order to adapt to different more or less unaccessible sites.
is there a way to stop windows screen reader event interception ?
You can stop some form of interception by calling preventDefault in your event listener function, if the click event is generated by the browser.
By doing so, you can actually do something different on click and on enter. But ask yourself first if it is really justified. Think about my first point above.
However, you can't prevent screen readers from intercepting keyboard events, translate them to something else and send or don't send them to your page.
There exists the ARIA application mode, but it has several important implications, so you shouldn't use it unless you have true good reasons.
To wrap up, the best is probably to adapt your code so that click and enter do the same thing, and that either or both event can be sent.
adding role="application" to the container div fixed it.

How to disable browser back button in AngularJS?

i want disable browser back button and refresh button. in angular
example my source
page source :
"use strict";
.controller("wizardSecondController", function($scope, $state, $stateParams, wizardManager) {
$scope.$on("$viewContentLoaded", function(event, data) {
});
i want prevent browser back and refresh .
please answer .
If you want to disable browser back button in angular, please try out the following code. It may help.
$scope.$on('$locationChangeStart', function(event, next, current){
event.preventDefault();
});
It's not a very straight forward thing in Angular.js but you can use JavaScript function - window.onhashchange to disable to back button.
Take a look at this link, you might get better ideas.
Use javascript event
window.onbeforeunload = function(e) {
var dialogText = 'Dialog text here';
e.returnValue = dialogText;
return dialogText;
};
refer
I shall give you advice as to disabling the back button:
Strictly speaking it isn't "possible" if using standards, but there are workarounds.
There is the window.history object which includes a small API.
But it doesn't allow you to double check for states/pages before the user surfed to your site. Obviously for security reasons and not by accident or missing implementation.
There's various checks for the usage of navigating back in the history and several posts about that topic, but none is helpful as to when it comes to the point the user leaves your page and goes beyond your accessible history.
As to that, check on the events
onhashchange
onpopstate (be aware IEs implementation thereof is half-baked, even in IE11 --> in my case it didn't respond to mouse interaction, only to js history.*()
If you want to catch the user on your site for some hopefully incredibly good purpose:
Create a duplicate entry of your home page on the first homepage-hit via window.history.pushState and instantly window.history.forward() --- (this works especially well and unnoticable on SPAs)
Reiterate that procedure every time the user navigates to your homepage/lowest_level_parent_state ...
Et voila ...
In my case I can't even escape our page if I hold down the backspace button ...
Another convenient option would be to put the page into fullscreen mode if feasible :)
Cheers, J

Flash Microphone Event Resize

I have been recently studying and learning Flash AC3 and my intention was to make a small voice recorder for my website. I have been using google and the search engines and get different answers here and there but still it is not exactly working properly.
The problem I am having is, the flash plugin is 215x50 pixels. I know that unless it is 215x138 pixels, the flash player security panel will automatically NOT open.
I devised a work around which is that if and when the security is being called to open, I would resize the DIV the flash object is in using a javascript function called ResizeFlash to a size of 215x138 and then back again to 215x50 after the user makes a choice whether or not they allow the microphone.
Now I have been scratching my head for a few days because I DO get the following code to work and it does resize the DIV, but it does not resize the DIV back. I think I might have the call to ResizeFlash in the wrong place (???). I am not familiar enough to know where it might be wrong.
I keep rearranging the code to see if that would work and I would get times where it does resize to 215x138, open the Security Panel, then resize back to 215x50 but then the recording would not begin, as if I were stuck somewhere in a loop.
I hope that someone can please take some time and just take a glance at this code and show me the right way to handle this. Thank you very much!
Here is the code:
public function Main():void
{
recButton.stop();
submitButton.enabled = false; // These reset everything, maybe in wrong place??
activity.stop();
addListeners();
mic = Microphone.getMicrophone();
if (mic == null)
{
// no camera is installed
}
else if (mic.muted)
{
// user has disabled the access in security settings
mic.addEventListener(StatusEvent.STATUS, onMicStatus, false, 0, true); // listen out for their new decision
Security.showSettings('2'); // show security settings window to allow them to change security settings
}
else
{
// you have access
mic.setUseEchoSuppression(true); //... also this might be in wrong place?
// .. I would like this to always be on
}
}
private function addListeners():void
{
recButton.addEventListener(MouseEvent.MOUSE_UP, startRecording);
submitButton.addEventListener(MouseEvent.MOUSE_UP, onSend);
recorder.addEventListener(RecordingEvent.RECORDING, recording);
recorder.addEventListener(Event.COMPLETE, recordComplete);
activity.addEventListener(Event.ENTER_FRAME, updateMeter);
}
function onMicStatus(event:StatusEvent):void
{
if (event.code == "Microphone.Unmuted")
{
mic.removeEventListener(StatusEvent.STATUS, onMicStatus);
ExternalInterface.call('ResizeFlash', '215', '50'); // When the user presses allow, resize the div back to 215x50
}
}
private function startRecording(e:MouseEvent):void
{
recorder.record();
e.target.gotoAndStop(2);
recButton.removeEventListener(MouseEvent.MOUSE_UP, startRecording);
recButton.addEventListener(MouseEvent.MOUSE_UP, stopRecording);
}
private function stopRecording(e:MouseEvent):void
{
recorder.stop();
e.target.gotoAndStop(1);
recButton.removeEventListener(MouseEvent.MOUSE_UP, stopRecording);
recButton.addEventListener(MouseEvent.MOUSE_UP, startRecording);
}
I know that I have something in there in the wrong order..! I appreciate any comments.
Resizing the app back to 215x50 in the Microphone's status event handler may be too soon, as you have suggested.
Just a hunch, but that status event is dispatched immediately when the user clicks the "Allow" radio button in the Flash security panel. The panel is still open. In fact, if you leave it open and click between allow/deny it will get dispatched each time...
When the security panel is up, there are some things you cannot do. I wonder if using ExternalInterface (to resize the app) is falling into this bucket.
I would suggest the following:
Test your resize functionality without the security panel in the mix. Make sure this code successfully resizes the app in both directions.
Then have a look at this question about how to detect when the user actually closes the security panel. There are two approaches there, one is very hacky (the BitmapData.draw() hack) but I know it works. I suggest trying the second one, and commenting/upvoting there if it does work (I will too). It's a more elegant way to detect when the user closes the dialog, but I haven't had a chance to try it.
When you detect the dialog is closed, resize the app.

ASP.NET/jQuery Post-Back, but not when using browser's "Back" button

I'm working on an ASP.NET Web Project with some AJAX magic. As my GridView's data needs up to 15 seconds to be gathered, I send the page to the client and fire an asynchronous update of an UpdatePanel via jQuery/JScript (see below).
This works well, so far. Now I'd like to skip this step when the user navigates to the next page (e.g. record detail view) and comes back via the "Back" button. Is there a way to get his, and what's the most elegant one?
This one does not work (hasDonePostBack's value isn't kept by the browser):
var hasDonePostBack = false;
function fRefreshAsyncOnce(id, param) {
$(document).ready(function() {
if (!hasDonePostBack) {
__doPostBack(id, param);
hasDonePostBack = true;
}
});
}
Any help would be great!
The reason why this is important: Regetting the data takes another 15 seconds. Moreover, the grid is working with controls and more client script (e.g. checkboxes that can be checked, CSS classes that are toggled, etc.), and all this should be the same after returning.
Cheers,
Matthias
You may want to look at the history point feature; you may be able to take advantage of that for this feature: http://msdn.microsoft.com/en-us/library/cc488548.aspx
However, that is the nature of the beast when triggering client-side operations... the other option is allowing the user to cancel the postback (or try to interpret a way to cancel it yourself) using this technique: http://msdn.microsoft.com/en-us/library/bb398789.aspx

How can I control the action of onbeforeunload in IE?

I've got a problem about onbeforeunload recently that I need to pop up a voting page when users try to close their IE browsers.I did it by using:
<body onbeforeunload="makevote()">
And the main structure of makevote() in javascript is as follows:
function makevote()
{
comet.distruct();
if(csid != null && isvote == null)
{
window.event.returnValue = false
window.event.returnValue='press “cancel” to vote please!'
showComDiv(popvote,"popiframe",400,120,'your vote here','dovote()');
}
}
In last three months this voting function performed so ugly that I got only less than 8,000 votes from more than 4,50,000 vistors.I think the problem is, when the users try to close their browsers,the onbeforeunload property pops up a comfirm box which covered my voting box while most users click the OK button,which means close comfirming is done,as a habit.So my question is how can I control the comfirming box made by onbeforeunload myself? For example if I click the "OK" ,I'll go to the voting box instead of closing my IE.So far what I can do is only defining the message it shows.And is there any other better way to do this?Help would be greatly appreciated!
Regards
Quite simply, you can't.
This is built-in behaviour, designed to only allow very minimal changes for security purposes. It's the same in every browser; FF, Chrome, etc, all will behave the same way.
The primary purpose for the beforeunload is for things like allowing the users the option to save changes before their changes are lost.
Besides, if your users are leaving, it's already too late - they won't want to answer a survey anymore, they're done!

Categories

Resources