Flash Microphone Event Resize - javascript

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.

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.

Linking into a page with a hash fragment (so user lands at specific content on page) issues

The Feature I Want:
I want to give a user a link like mysite.com/foo#bar so when they hit this link they land on the page foo and are scrolled half way down the page to the content with the id bar. It should be noted that this link will always be clicked from off site or typed into the address bar manually, the user will not already be on the page with all assets loaded.
Also fyi I am using angular and the page in question each bit of content is in an element directive, and in each directive template there are images
The Issue:
Easy enough right? Well I'm running into some problems, most of the time it works, but maybe 40% of the time it doesn't and the user lands above the content, I believe this is because the browser scrolls to the correct point on the page, but then slightly afterward images are loaded in above it pushing the rest of the page down, leaving the user in a random unintuitive spot. (For some reason the failure rate seems to be worse on iPhones...)
What I've Tried So Far:
In a run function I look for a hash fragment on any route and scroll to it if it exists.
if($location.hash()) {
$anchorScroll();
}
I've tried:
Wrapping it in a timeout
This works sometimes but is obviously not consistent, sure I can set it to 500ms and on a great wifi connection it's fine, but not on a mobile with poor signal
listening for $viewContentLoaded
Too fast, ui-router seems to fire this event way before the page is rendered
Emitting an event in each post-link function for all directives on the page.
link: function ($scope) {
$scope.$emit('loadingFinished');
Then picking that up again in the run function
$scope.$on('loadingFinished', function () {
$timeout(doAnchorScroll, 500);
}
This raised the success rate but still wasn't foolproof. And I witnessed it leaving the user stranded in weird spots mainly on iPhones.
Can anyone suggest a way of detecting a moment where it is safe to scroll, or perhaps some other way of ensuring landing in the correct spot?
Two things - first is a user-scroll should prevent it - you don't want to be scrolling the view if they've already scrolled. Second is listening for the images to finish loading.
Listening for the images is quite easy:
$("img").one("load", $anchorScroll);
Then in $anchorScroll I'd suggest checking if all images have loaded, and returning immediately if not (bonus points if you only check images above the anchor - but only doing a quick reply):
var scrolled = false;
function $anchorScroll() {
var allLoaded = true;
$("img").each(function() {
if (!this.loaded) {
return allLoaded = false;
}
});
if (scrolled || !allLoaded) {
return;
}
...
The scrolling is possibly slightly harder - you can check for scroll events, but they are slightly different between platforms - and might even get fired for the manual scroll - if you find that happens then simply have a global that says "I'm scrolling here" and ignore it, otherwise:
$(document).one("scroll", function() { // Use ".on" if this gets fired for code...
scrolled = true;
});
Note that you probably don't need to care about failed image loads, or ones that have already loaded, since your initial call to $anchorScroll() will catch them.

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!

showSettings callback in Flex?

I am pretty new to flex, so forgive me if this is an obvious question.
Is there a way to open the Security.showSettings (flash.system.Security) with a callback? or at least to detect if it is currently open or not?
My flex application is used for streaming audio, and is normally controlled by javascript, so I keep it hidden for normal use (via absolute positioning it off the page).
When I need microphone access I need to make the flash settings dialog visible, which works fine, I move it into view and open the dialog.
When the user closes it, I need to move it back off the screen so they don't see an empty flex app sitting there after they change their settings.
thanks :)
If you do something like this, it will work in some situations:
var mic:Microphone = Microphone.getMicrophone();
mic.addEventListener(StatusEvent.STATUS, onMicStatus);
If you are just trying to use the microphone and relying on Flash to pop up the dialog to ask the user for permission, Flash will open a dialog with two buttons, Allow and Deny. When the user clicks one of the buttons the StatusEvent will fire, the dialog will close, and you can move the flex app out of the way.
If you are manually opening the settings panel (via Security.showSettings), you get the panel with Allow and Deny radio buttons, and the event will fire when the user clicks on the radio buttons, not when they close the panel, which is probably of less help to you.
Update: flex 4 solution
So when I moved to the flex 4 and started compiling my mxml with adobe's open source mxmlc compiler, the solution below no longer worked because the alert doesn't lose focus when you're in the settings anymore.
As far as I could tell I had to move to a less elegant solution where the user must click "OK" on the alert box every time they are done with the settings.
Here is the new code:
private function setup_smart_hide():void {
// Call this function whenever you make the flex app visible (or add it
// to a show_flex() function if you have such a thing set up)
alert = Alert.show('Click "OK" to continue.', 'Thanks!', Alert.OK, null, function(e:CloseEvent):void {
// calls the external javascript to hide the flex app
hide_self();
});
}
OLD: (flex 3) Got this working...
private function setup_smart_hide():void {
alert = Alert.show('Thanks');
alert.addEventListener(FocusEvent.FOCUS_IN, function(event:FocusEvent):void {
// javascript to hide the flex app
ExternalInterface.call("SB.flex.hide");
});
alert.addEventListener(FocusEvent.FOCUS_OUT, function(event:FocusEvent):void {
// javascript to show the flex app
ExternalInterface.call("SB.flex.show");
});
alert.setFocus();
}
Which is run first thing in the init() function... the only problem is (like Wesley said), the focusOut event occurs when the flex app itself loses focus as well.

iFrame Validation

I currently have an iframe within my main page that has a number of checkboxes that need to be actioned prior to leaving the iframe. i.e, if the user commences checking the checkboxes and half way through they then click back on the main page, i.e leaving the iframe, I would like to be able to trap/validate that they have left the iframe and prompt them with a message indicating this, say with a "Note: You will lose all data entered here - Leave: Yes/No?" type message.
Prompting a User to Save When Leaving a Page. This 4guys article sounds like what you need. It talks about the onbeforeunload event. There's some awesome posts here on stackoverflow about onbeforeunload too.
It appears that onbeforeunload indeed does not fire for an iframe. Bugger!
Here's some sample code that should work though. This will only work if you're in the same domain, otherwise same origin policy will prevent the iframe from talking back to the parent.
I also haven't tested these in many browsers so YMMV.
You've got two options here, depending on where you want to put the prompt for changes logic.
Option one involves the iframe telling the parent window when there's changes.
Parent window javascript:
window.onbeforeunload=closeIt;
var changes = false;
function closeIt()
{
if (changes)
{
return "Yo, changes, save 'em?";
}
}
function somethingChanged() {
changes=true;
};
Iframe javascript:
$(function() {
$('input').change(parent.somethingChanged);
});
Option two involves the iframe taking control over the parent window's onbeforeunload
Parent window javascript:
There is none :-)
Iframe javascript:
$(function() {
parent.window.onbeforeunload = myCloseIt;
$('input').change(somethingChanged);
});
var changes = false;
function myCloseIt()
{
if (changes)
{
return "Yo, changes, save 'em?";
}
}
function somethingChanged() {
changes=true;
};
In either option the naive changes variable could be beefed up a bit, probably using techniques from the 4guys article, to see if there's really been any changes.
If they're on different domains, but you're still in charge of "both sides" of the HTML, there's still some options, they're just harder.
xssinterface is a library that uses postMessage and location hashes and secret voodoo black magic to communicate cross site.

Categories

Resources