I built this incredibly brilliant scrolling thumbnail image viewer for a client in Flash Actionscript 3. (Basically it just scrolls up or down depending on the mouse position). It works so so, (I can never get the percentages right so that it shows the top most image) but, that's beside the point. What is REALLY irking me is when I have the browser window open with my .swf loaded and I click on another app on my desktop, the stupid scrolling thumbnail area in the browser window starts to freak out.
"Where is my mouseY??!?!?!?" I assume it is thinking.
Is there a stage.Unfocus event I can tell my scrolling thumbnail area to STFU with?
I'd even consider writing some Javascript to call a flash function, if that's a preferred technique.
function checkMousePos(e:Event):void
{
if(mouseX < 145){
try{
var sHeight:int = MovieClip(root).stageHeight;
}catch(Error){
trace("stage not loaded");
}
if(mouseY > (sHeight/2) + 100){
if(tHolder.y-50 > - (compHeight-sHeight)){
Tweener.addTween(tHolder, {y:tHolder.y - 90, time:1,transition:"easeOutCubic"});
}
}else if(mouseY < (sHeight/2) - 100){
if(tHolder.y+50 < 80){
Tweener.addTween(tHolder, {y:tHolder.y + 90, time:1,transition:"easeOutCubic"});
}else{
Tweener.addTween(tHolder, {y:80, time:1,transition:"easeOutCubic"});
}
}
}
}
I suggest detecting the window focus events onblur and onfocus ( http://www.devguru.com/technologies/ecmascript/quickref/evHan_onBlur.html ) in Javascript then sending an enable / disable call through to the SWF file using ExternalInterface ( http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/external/ExternalInterface.html ) So inside your HTML you might have something like this (assuming swfobject here, but this isn't necessary http://code.google.com/p/swfobject/ ):
swfobject.embedSWF("mySWF", "mySWFId", swfWidth, swfHeight, "10.0.0", "", flashvars, params, attributes);
window.onblur=function () {
if ( document.getElementById("mySWFId").disableMouseScrolling) {
document.getElementById("mySWFId").disableMouseScrolling();
}
}
window.onfocus=function () {
if ( document.getElementById("mySWFId").enableMouseScrolling ) {
document.getElementById("mySWFId").enableMouseScrolling();
}
}
And inside your SWF file some equivalent ExternalInterface code to hook up the methods:
public class MyApplication extends ...
{
public function MyApplication ():void
{
ExternalInterface.addCallback("disableMouseScrolling", disableMouseScrolling);
ExternalInterface.addCallback("disableMouseScrolling", enableMouseScrolling);
...
}
private function disableMouseScrolling ():void
{
}
private function enableMouseScrolling ():void
{
}
...
}
Hope this helps. I've used it with IE8, Firefox 3 and Crome 4.
Regards,
stage.addEventListener(Event.MOUSE_LEAVE, function(e:Event):void {});
Related
I have a method to detect the notch on iPhones and it works...but I just found out it doesn't work well. About 1 out of 5 app starts, I see the function reporting that the phone doesn't have the notch when in fact it does.
When my app deviceReady() state is activated, I then check to see if the device has the notch then assign the true/false value to a variable that I use later on. As mentioned, about 1 in 5 times it returns false. I think its a timing thing, the function is evaluating the DOM before the DOM has fully loaded causing the detection method to fail.
function hasNotch() {
if (CSS.supports('padding-bottom: env(safe-area-inset-bottom)')) {
var div = document.createElement('div');
div.style.paddingBottom = 'env(safe-area-inset-bottom)';
document.body.appendChild(div);
setTimeout(function() {
var calculatedPadding = parseInt(window.getComputedStyle(div).paddingBottom, 10);
document.body.removeChild(div);
if (calculatedPadding > 0) {
errMgmt("preIndex/hasNotch ",101.1,"READY: Notch Detected") ;
return true ;
} else {
errMgmt("preIndex/hasNotch ",101.2,"READY: Notch Not Detected") ;
return false ;
}
},100) ;
} else {
errMgmt("preIndex/hasNotch ",101.3,"READY: Notch Not Supported") ;
return false ;
}
}
$ionicPlatform.ready(function() {
$rootScope.hasNotch = hasNotch() ;
...
}) ;
Then in my landing page controller:
.controller('HomeCtrl', function($rootScope,$scope,$state,$stateParams,$ionicModal,$q,apiService) {
if ($rootScope.hasNotch == true) {
.. do css stuff ..
}
}) ;
When it fails to detect, its always the message READY: Notch Not Detected returned...not once has it returned the READY: Notch Not Supported which means the CSS.supports is working, but not part regarding the calculatedPadding.
The true/false value is needed in the Controller of the landing page, and when it fails its causing CSS layout issues. Either the hasNotch() is too slow and the app init is triggering the landing page faster than the response from hasNotch() or there is actually something else wrong with my function.
On a side note, I have researched different methods to detect the notch on Android phones - the two plugins seem to have issues and/or aren't really supported anymore. Was hoping for a solid solution for Android....or even better, a universal solution for both iOS types.
I came up with a solution but I still hoping there is a better way. Something that can detect a phone notch during app initialization versus having to rely on DOM evaluations. I have tested the app over 25 times and so far this new method has detected the notch every single time. As I code other things I will continue to evaluate the outcome, but so far so good. Here is what I did.
I removed the check from deviceReady:
$ionicPlatform.ready(function() {
$rootScope.hasNotch = hasNotch() ;
...
}) ;
And in my landing page controller:
.controller('HomeCtrl', function($rootScope,$scope,$state,$stateParams,$ionicModal,$q,apiService) {
$scope.hasNotch = null ;
var watchNotch = $scope.$watch('hasNotch',function() {
//begin watching for var change
deviceData.hasNotch = $scope.hasNotch ;
$scope.doSomething() ;
watchNotch() ; // kill watch
}) ;
if (ionic.Platform.isIOS()) {
$scope.hasNotch = hasNotch() ;
} else {
deviceData.hasNotch = false ;
$scope.doSomething() ;
watchNotch() ; // kill notch
}
}) ;
Now I just need to go find a reliable plugin to detect Android notches....easier said than done.
I am having issue fixing the header after scrolling, I tried a lot of stuff but can't get it to work. I checked this thread but it doesnt work for me: Angular 4 #HostListener Window scroll event strangely does not work in Firefox . This is my component structure:
Layout
Steps
Routes
Inside steps is my header which I want to fix, after scrolling for 50px. Inside Layout is some other content like a div with logo background (above the content of steps).
This is what I tried inside Steps.ts
#HostListener('window:scroll', [])
onWindowScroll() {
const number = window.scrollY;
if (number > 40) {
this.fixed = true;
} else if (this.fixed && number < 10) {
this.fixed = false;
}
}
but the problem is that scroll is not triggering at all. I found examples
where scroll logs the event, but for me it doesn't work (I tried with $event as well). Anyone has a solution?
Found a solution. On my layout component I put a function
(scroll)="onWindowScroll($event)"
and in layout component i used:
#HostListener('window:scroll', ['$event'])
onWindowScroll($event) {
const number = $event.target.scrollTop;
if (number > 40) {
this.fixed = true;
} else if (this.fixed && number < 10) {
this.fixed = false;
}
}
I removed Steps component since I didnt need it anymore, all the content is inside layout now.
In Angular 5+ it works a little differently:
const number = $event.target.scrollingElement.scrollTop || $event.target.documentElement.scrollTop;
Since some people come via Google to this question:
I'm quite a fan of moving logic like this into something re-useable. For Angular this would mean a directive. Therefore as I run into this issue myself I created a library from my code that at least has some tests and support across many browsers. So feel free to use this tested piece of code instead of polluting your components with more code.
https://w11k.github.io/angular-sticky-things/
With the code I see in the answer I did run into some issues. In another SO I found this solution. It is crucial to determine the offsetY of the header element correctly.
// Thanks to https://stanko.github.io/javascript-get-element-offset/
function getPosition(el) {
let top = 0;
let left = 0;
let element = el;
// Loop through the DOM tree
// and add it's parent's offset to get page offset
do {
top += element.offsetTop || 0;
left += element.offsetLeft || 0;
element = element.offsetParent;
} while (element);
return {
y: top,
x: left,
};
I have the following problem, I need to disable the native Keyboard completely. The keyboard should only show when I call the show() and hide when I call the close() function (this will be on a Button for the user to toggle the Keyboard).
The Keyboard showing on clicking the Field and on Focus needs to be completely disabled.
On Stackoverflow I found this:
InputMethodManager im = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
im.hideSoftInputFromWindow(editText.getWindowToken(), 0);
So my thought was In the "Init"(Line 52 in the IonicKeyboard.java) I need to change it.
if ("init".equals(action)) {
cordova.getThreadPool().execute(new Runnable() {
public void run() {
//new Logic on init
View v = cordova.getActivity().getCurrentFocus();
((InputMethodManager) cordova.getActivity().getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(v.getWindowToken(), 0);
DisplayMetrics dm = new DisplayMetrics();
cordova.getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm);
final float density = dm.density;
//http://stackoverflow.com/a/4737265/1091751 detect if keyboard is showing
final View rootView = cordova.getActivity().getWindow().getDecorView().findViewById(android.R.id.content).getRootView();
OnGlobalLayoutListener list = new OnGlobalLayoutListener() {
int previousHeightDiff = 0;
#Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
rootView.getWindowVisibleDisplayFrame(r);
PluginResult result;
int heightDiff = rootView.getRootView().getHeight() - r.bottom;
int pixelHeightDiff = (int)(heightDiff / density);
if (pixelHeightDiff > 100 && pixelHeightDiff != previousHeightDiff) { // if more than 100 pixels, its probably a keyboard...
String msg = "S" + Integer.toString(pixelHeightDiff);
result = new PluginResult(PluginResult.Status.OK, msg);
result.setKeepCallback(true);
callbackContext.sendPluginResult(result);
}
else if ( pixelHeightDiff != previousHeightDiff && ( previousHeightDiff - pixelHeightDiff ) > 100 ){
String msg = "H";
result = new PluginResult(PluginResult.Status.OK, msg);
result.setKeepCallback(true);
callbackContext.sendPluginResult(result);
}
previousHeightDiff = pixelHeightDiff;
}
};
rootView.getViewTreeObserver().addOnGlobalLayoutListener(list);
PluginResult dataResult = new PluginResult(PluginResult.Status.OK);
dataResult.setKeepCallback(true);
callbackContext.sendPluginResult(dataResult);
}
});
return true;
}
return false; // Returning false results in a "MethodNotFound" error.
}
Sadly this does not work at all...
I think I have to change the close / show function too but I am not really sure what the correct code is, and I dont know if this change would affect other Keyboard behaviour. (But I basically need Focus without Keyboard)
I also found this Cordova Plugin
which looks very promising, but I decided to change this in the Ionic Keyboard Plugin, because I need the same behaviour in Windows too.
Very glad if someone could help me out here.
Regards Christopher
This can be accomplished by disabling all inputs with ng-disabled and later showing the keyboard with the Ionic Keyboard Plugin.
If you do not want the inputs to appear differently when disabled, you can override this style with CSS using the :disabled selector.
Hide on load:
<input ng-disabled="hideKeyboard">
hideKeyboard = true;
Show on function:
<input ng-disabled="hideKeyboard">
function showKeyboard(){
hideKeyboard = false;
cordova.plugins.Keyboard.show();
}
When an iOS 8 device running a Web Application (i.e. launched from a shortcut on the Home Screen) returns from it's Sleep state all asynchronous web requests made fail to trigger the OnUpdateReady callback.
The problem is quite easy to reproduce - simply put the two code files below on any web server and give it a try.
Has anyone else run into this issue? If so is there any workarounds?
I'm posting this to try to attract attention to this bug in iOS 8 that has essentially ruined all of my web applications - we've had to recommend to NOT upgrade beyond iOS 7. And yes, I've posted the problem on Apple Bug Reporter but I think no one is looking at these since it has been a long time.
app.manifest
CACHE MANIFEST
# 2014-09-24 - Test
CACHE:
default.html
default.html
<!DOCTYPE html>
<html manifest="app.manifest">
<head>
<title>Test Harness</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
<meta name="HandheldFriendly" content="true" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<script language="javascript" type="text/javascript">
var Test = new function () {
var _GetEnd = function (oResult) {
var sResult = ': ' +
((oResult.Value === true)
? 'Success'
: 'Failure<br>' + oResult.Reason) +
'<br>';
var oLog = document.getElementById('idLog');
oLog.innerHTML = (new Date()) + sResult + oLog.innerHTML
setTimeout(_GetBegin, 1000);
};
var _GetBegin = function () {
var sURL = 'app.manifest';
var hAsyncCallback = _GetEnd;
try {
var oRequest = new XMLHttpRequest();
oRequest.onreadystatechange =
function () {
if (oRequest.readyState != 4) return;
if (oRequest.status != 200) {
hAsyncCallback({ Value: false, Reason: oRequest.responseText });
} else {
hAsyncCallback({ Value: true, Reason: null });
}
};
oRequest.open('GET', sURL, true);
oRequest.send(null);
} catch (e) {
alert('Critical Error: ' + e.message );
}
};
this.Start = function () { _GetBegin(); }
};
</script>
</head>
<body onload="Test.Start();">
<ol>
<li>Put both app.manifest and default.html on a web server.</li>
<li>Make sure this page is being launched from the Home screen as a web application.</li>
<li>Press the sleep button while it is running.</li>
<li>Press the wake button and unlock the phone to get back to this screen.</li>
<li>Under iOS7x the page continues, under iOS8 the onreadystatechange never gets called again.</li>
</ol>
<div id="idLog"></div>
</body>
</html>
Installing iOS 8.1.1 fixes this.
I am also seeing the same issue, though my example is much simpler. Simply have a webclip application with
<script>
window.setInterval(function(){
console.log("Johnny Five Alive! : " + new Date());
},1000);
</script>
on the page. Inspecting the console, after the sleep wakes up, no more console output. This works fine on iOS7 (my actual application is a complicated angularJS thing, I just boiled down the issue to this). Have you had any response on your bug report?
Our workaround (for AJAX) is:
Detect iOS8 (indeed 8.0.2 still has this) (also see this for other workaround: How to resume JavaScript timer on iOS8 web app after screen unlock?)
Remove the normal eventListeners, but keep the onProgress one
...
this.onProgress = function(e)
{
var position = e.position || e.loaded;
var total = e.totalSize || e.total;
var percentage = 0.0;
if(total != 0)
{
percentage = position / total;
}
if(percentage == 1) {
if( this.isIOS8() ) {
recovery_uuid.get(uuid, _.bind(this.ios8ScriptReturn, this));
}
}
}
...
//this gets called when the script with this UUID is injected
this.ios8ScriptReturn = function(uuid, value) {
//then we create a simpler non real one
this.xhr = {};
this.xhr.readyState = 4;
this.xhr.status = 200;
this.xhr.responseText = value;
this.xhr.onreadystatechange = null;
this.xhr.isFake = true;
//fake stateChnage
this.onReadyStateChange();
}
add a UUID to each request
if( this.isIOS8() ) {
ajaxInfo.url += '&recoveryUUID='+ajaxInfo.uuid;
}
Then still perform the XHR Send (that actually works fine, server gets and send back fine).
server Side save the 'result' in database/file with the UUID as index/part of filename
//detect the need for saving the result, and save it till requested
if(isset($_GET['recoveryUUID'])) {
$uuid = $_GET['recoveryUUID'];
RecoveryUUID::post($uuid, $result_json_string);
}
On the client create a little helper global object that listens to the code injects and redirects them to the onProgress handler.
var RecoveryUUID = (function (_root) {
function RecoveryUUID() {
this.callbacks = {};
}
var proto = RecoveryUUID.prototype;
proto.onLoaded = null;
proto.set = function(uuid, value) {
console.log('RECOVERY UUID: Received DATA: '+uuid+' value: '+value);
if(typeof this.callbacks[uuid] != 'undefined') {
this.callbacks[uuid](uuid, value);
delete this.callbacks[uuid]; //auto remove
}
if(this.onLoaded != null) {
this.onLoaded(uuid, value);
}
var script = document.getElementById("recoveryScript_"+uuid);
script.parentElement.removeChild(script);
}
proto.getURL = function(uuid) {
return "http://"+window.location.hostname+":8888/recoveryuuid/index.php?uuid="+uuid;
}
proto.get = function(uuid, callback) {
var script = document.createElement("script");
script.setAttribute("id", "recoveryScript_"+uuid);
script.setAttribute("type", "text/javascript");
script.setAttribute("src", this.getURL(uuid));
if(typeof callback != 'undefined') {
this.callbacks[uuid] = callback;
}
document.getElementsByTagName("head")[0].appendChild(script);
}
return RecoveryUUID;
})();
//global - just so the injected script knows what to call
recovery_uuid = new RecoveryUUID();
The script that is loaded immediately executes (pushes, since setInterval is dead as well).
// this is: http://"+window.location.hostname+":8888/recoveryuuid/index.php?uuid=...."
<?php
header('Cache-Control: no-cache, no-store, must-revalidate, post-check=0, pre-check=0 '); // HTTP 1.1. //iOS force this file to keep fresh
header('Pragma: no-cache'); // HTTP 1.0.
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header('Content-type: application/javascript; charset=UTF-8');
if(isset($_GET['uuid'])) {
$uuid = $_GET['uuid'];
$out = 'recovery_uuid.set('.json_encode($uuid).','.json_encode(RecoveryUUID::get($uuid)).');';
echo $out;
}
?>
Below is a simple filebased results implementation.
<?php
class RecoveryUUID {
static public function getFileName($uuid) {
return SOMESTATIC LOCATION.$uuid.'.json';
}
static public function post($uuid, $stdClassOrString) {
$data = '{ "data": '.json_encode($stdClassOrString).', "uuid": '.json_encode($uuid).' }';
file_put_contents(self::getFileName($uuid), $data);
}
//might not work first time as the script tag might request this file before it was written.
//so we wait just a bit.
static public function getFull($uuid) {
$tries = 10;
$filename = self::getFileName($uuid);
while ($tries > 0) {
if(file_exists($filename)) {
if (is_readable($filename)) {
$data = #file_get_contents($filename);
if($data !== FALSE) {
unlink($filename);
return $data;
}
}
}
$tries = $tries -1;
usleep(250000);//wait 0.25 secs ...
}
$data = new stdClass();
$data->uuid = $uuid;
$data->data = 'ERROR RECOVERYUUID: timeout on reading file';
return $data;
}
static public function get($uuid) {
$decoded = json_decode(self::getFull($uuid));
if( $decoded->uuid == $uuid ) {
return $decoded->data;
}
return null;
}
}
?>
As we do not use JQuery all we needed to do was add the extra logic in our Ajax class, and of course the Saving to Database for all requests..
Downsides:
Nasty
Will keep on adding memory footprint for each call (for us not an issue as the memory is cleared between window.location.href calls (we do not use SPA) so eventually will fall over.
Extra serverside logic.
Upsides:
Works until memory runs out (removing script tags, which we do does not remove the memory associated)
Comments:
You could of course just send everything with the 'call' but we wanted to have minimal server side impact (or not much work for us anyway) + we presume this will be fixed and means our 'user' code has 0 impact.
Weird, Apple just closed my bug and referred to the same bug number. Also a web app but I found css3 transitions to stop working after screen lock see below:
Engineering has determined that your bug report (18556061) is a duplicate of another issue (18042389) and will be closed
My report:
If you add an HTML app to the home screen and open it, all CSS3 transitions work correctly. Without closing the app and pressing screen lock the transitions seem to stop and can cause the ui to appear to freeze. For example if an absolute overlay is triggered (opacity:0 to opacity:1) it remains invisible making the app appear not to work
Ajax requests, Timer functions and WebkitAnimation are broken after a lock-screen on iOS8.
For the Ajax and Timer functions, we are using this solution in our system:
How to resume JavaScript timer on iOS8 web app after screen unlock? (link to the gitHub in the comment).
It is not exactly part of the question but I would like to share our workaround with CSS3 animations and events, since it may help somebody in the future.
For the webkitAnimation, we found that redrawing the element with the animation on, or more drastically the body would restart animations and events applied to them (webkitAnimationEnd for instance, which is used heavily by jquery-mobile).
so our code gives something like:
document.body.style.display='none';
setTimeout( function() { document.body.style.display = 'block'; }, 1);
You may or may not need the setTimeout function on the second statement. Most interesting thing is, once it has been redrawn, it will never go frozen again no matter how many lock screens come up after that...
The webapp environment is so horribly broken when resuming after screen lock I don't see how (a) Apple could ignore this indefinitely and (b) how any webapp can confidently work around the crippled environment.
My solution is to detect resume after sleep using setInterval (which stops working after the resume) and then posting an alert() to the user stating that the app has to be re-launched from the home screen because iOS cannot resume it.
It just so happens that alert() is also broken after the resume--it displays the alert and then the webapp exits to the home screen when the user hits OK! So this forces the user to re-launch.
The only issue when the user re-launches is the handling of apple-mobile-web-app-status-bar-style. I have this set to black-translucent which normally sets the status bar content to black (on light backgrounds) or white (on dark backgrounds). On the first re-launch after resume, the status bar content is always black. On subsequent re-launches (not interrupted by sleep/resume) the behavior returns to normal.
What a mess. If I was responsible for this at Apple I'd be embarrassed, and here we are with 8.1 and it still hasn't been fixed.
I have some code running on my website which will detect if a div with the id, photo, is showing on the screen or is scrolled onto the screen. If the div is showing, a class is added to the div which will cause a background image to load inside the div. The intent is to lazyload the image so that the site loads faster.
It is working great in all browsers except for IE 6/7. Can someone tell me what is wrong with the below code that prevents it from working in these IE browsers?
function $(a){
return document.getElementById(a)
}
function scrll(){
function a(d){
var f=d.offsetTop,
e=d.offsetLeft,
c=d.offsetWidth,
b=d.offsetHeight;
while(d.offsetParent){
d=d.offsetParent;
f+=d.offsetTop;
e+=d.offsetLeft
}
return(f<(window.pageYOffset+window.innerHeight)
&&e<(window.pageXOffset+window.innerWidth)
&&(f+b)>window.pageYOffset&&(e+c)>window.pageXOffset)
}
if(a($("photo"))){
$("imgholder").className="pic11 pic21";
if(window.removeEventListener){
window.removeEventListener("scroll",scrll,false)
}else{
if(window.detachEvent){
window.detachEvent("onscroll",scrll)
}else{
window.onscroll=null
}
}
}
}
if(window.addEventListener){
window.addEventListener("scroll",scrll,false);
}else{
if(window.attachEvent){
window.attachEvent("onscroll",scrll);
}else{
window.onscroll=scrll;
}
}
setTimeout(scrll,1);
The code is active on my website: http://www.ericperrets.info/
IE doesn't have innerHeight. Use this function instead:
function getWindowHeight()
{
if (window.innerHeight) return window.innerHeight;
if (window.document.documentElement.clientHeight) return window.document.documentElement.clientHeight;
return window.document.body.clientHeight;
}
Also, a good article explaining differences between browsers is at http://www.howtocreate.co.uk/tutorials/javascript/browserwindow