save current window to use it at resume - javascript

i am trying to save the current window in focus event to app properties like this
$.profileWin.addEventListener('focus', function(e) {
Ti.App.Properties.setObject("curwin", $.profileWin);
});
i am doing this for more than 1 window
but at focus of window i get this error
-[TiUIWindowProxy encodeWithCoder:]: unrecognized selector sent to instance 0x1ea19c00";
how do i save the the current window and have it accessed when the iPhone resumes from its suspended state

When you try to save a value in Ti.App.Properties it will simply be converted to at string of text. I'm not sure setObject will accept anything else but JSON-objects (and a Ti.UI.Window is not a JSON-object).
That being said, saving the actual Window-object might not be a good idea, as the different dependencies might have been removed from memory, when you try to reload the window.
A better approach would be to save the relevant properties of the Window (and other values that you might need to restore the current state of the Window) and the re-layout the Window once it gains focus.

Related

Custom Javascript Variable Returns Different Value on History Change

I have setup a Custom JavaScript variable that works intermittently. The function is simply designed to return true or false if a text is contained on the page.
The below code works fine when the page is loaded directly from the URL bar and when executed in the developer tools console. When running the function in the console, the function indeed turns true. When the code is executed within debug mode in GTM, the value returns false when a history change event occurs.
function() {
var content = document.body.innerText;
var query = "text to search";
if (content.search(query) > -1 ) {
return true;
} else {
return false;
}
}
Any assistance/insight is very much appreciated!
To me this seems like expected behavior. Since you are talking about history changes, you are probably working with a single page application, or some other page where the DOM is changed after the initial page load.
Custom Javscript variables evaluate a function and return the result each time you reference it. How I imagine the flow of operations goes is this.
Page Loads (target text is in the page body) -> Custom JS evaluates on page view and returns true -> User presses some button -> DOM is modified to display new content (target text is removed and no longer present -> History change occurs -> Custom JS evaluates again, the text is no longer present so returns false.
If the target text is still present after the history change, then I can understand why we have some unexpected behavior. The history change trigger is based off of the push state api so what could be happening is that the pushState() function is called before the DOM is finished being modified. In this case, the text isn't present at time of the history change event even though it is shortly afterwards.
You could change the page so pushState() is only called after the DOM is done being modified, use a custom event as a trigger instead (again, pushing it after the DOM is done being modified), or use a different trigger like the element visibility trigger that will only fire after the new DOM elements you want to target appear on-screen.

Detecting when a variable changes in javascript

I have a chrome app that I want to correctly resize (dimensions proportional to the screen width) on resolution change. I have written a function that redraws the app with the correct dimensions, now I want to execute it only when it needs to.
A resolution change causes screen.width to change, but (probably unsurprisingly since they relate to different things) the "resize" event is not fired, and as far as I can tell no event is fired.
I know about the Proxy object (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) so I wrote some code which detects when a variable is set and executes my callback, this seemed to work but not in the instance of resolution change.
So I searched online and tried this https://gist.github.com/eligrey/384583 (which is essentially the answer provided in several stackoverflow questions on a similar topic, and indeed what I initially produced, albeit lacking the abstraction that the newish Proxy object offers).
This also seems to work (in the sense if I say manually set screen.width after having done screen.watch("width", () => console.log("hello")); and then do screen.width = 100; my callback is executed). But not in the instance of resolution change (in fact, perhaps most importantly, assigning this watcher seems to prevent screen.width getting assigned).
I have three questions
1) What is going on when I assign a watcher/proxy that's messing things up.
2) How could I find out what the browser is doing at this level of detail (what sends the trigger to change screen.width? I guess it is the OS, what does this look like)
3) Is there a better way to achieve what I was initially going for (the chrome app resizing).
Mostly I am interested in question 1) and don't care much about 3) any more.
To replicate my issue,
open a new tab in firefox or chrome
go to the developer console.
check screen.width, change resolution, observe that screen.width changes
Copy and paste the code from https://gist.github.com/eligrey/384583
Do screen.watch("width", (id, oldval, newval) => {console.log("hello"); return newval;});
Do screen.width = 100; and observe that hello is logged and screen.width is set to 100
Change resolution, observe that screen.width is not set.
Edit - As revealed after Bertrand's answer, the resize event may actually fire on resolution change, but this seems to be as a response to the resolution change forcing the boundary of the the window to get smaller, if the window is small then screen.width can change without firing a resize event.
What is going on when I assign a watcher/proxy that's messing things up.
The issue is that the width property is actually a getter, on Screen.prototype. It's not an ordinary value on window.screen:
console.log(window.screen.width);
console.log(window.screen.hasOwnProperty('width'));
// The property exists on the prototype instead, and is a getter:
const descriptor = Object.getOwnPropertyDescriptor(Screen.prototype, 'width');
console.log(descriptor);
If the width property were an ordinary property, composed of just a plain value, which was set by the browser via evaling
window.screen.width = 1500
then a proxy or the Object.watch polyfill would work, because you would be able to intercept the assignment to the .width property. This is why you see that, after assigning your own setter to window.screen.width:
Do screen.width = 100; and observe that hello is logged and screen.width is set to 100
It shows you hello - you're invoking the setter that you previously assigned to the screen property of window. In contrast, because the native built-in property is not a plain value which gets assigned to by the browser, your hello does not get logged when the screen changes. The situation is a bit similar to what's going on in this example snippet:
const obj = (() => {
let privateVal = 'propOriginal';
// privateVal changes after 500ms:
setTimeout(() => {
console.log('Changing privateVal to propChanged');
privateVal = 'propChanged';
}, 500);
// Return an object which has a getter, which returns privateProp:
return {
get privateProp() {
return privateVal;
}
};
})();
// At this point, if one only has a reference to `obj`,
// there is no real way to watch for changes to privateVal:
console.log(obj.privateProp);
// Assigning a custom setter to obj.privateProp
// will only result in observing attempted assignments to obj.privateProp
// but will not be able to observe the change to privateVal:
Object.defineProperty(obj, 'privateProp', { set(newVal) {
console.log('Observed change: new value is ' + newVal);
}});
setTimeout(() => {
obj.privateProp = 1000;
}, 2500);
As you can see, the setter function added to obj in the outer scope cannot capture the change to privateVal. This isn't exactly what's happening with window.screen, but it's similar; you do not have access to the underlying code structure that results in changes to the value returned by calling the built-in getter.
The built-in getter function on screen is composed of native code - this means that it's not an ordinary Javascript function. Functions composed of native code are always functions provided by the browser (or whatever environment the code is running in); they often cannot be emulated by any Javascript functions you write yourself. For example, only the window.history object can perform history actions like history.back(); if window.history gets overwritten, and you don't have a saved reference to it or any other history objects, there's no way to write your own function that can do history.back(), because .back() invokes privileged native code that requires an interface between the visible Javascript and the browser engine.
Similarly, the built-in window.screen getter, when called, returns a value not directly observable by plain Javascript. Without polling, the only other way to watch for a change is by listening for the resize event, as covered in the other answer. (This resize event, similar to the underlying value returned by window.screen, is managed by browser internals not observable otherwise.)
If the resize event does not get fired in response to a change in resolution - for example, if the browser window is small enough already that a change is not required for the smaller resolution - then the resolution change does not result in any event being fired, which means there's unfortunately no way to listen for it, aside from polling. (You can try it for yourself, it doesn't look like any other events are triggered on resolution change)
One could probably write (or tweak) a browser engine which listens for a resolution change from the OS and dispatches a Javascript event when found, but doing so would require knowledge far beyond Javascript - feel free to browse Chromium's source code for details, but it's pretty complicated, and probably opaque to one without experience in the languages used.
According to Mozilla, screen resize event is only fired on window object. Therefore, you should add listener to window not to screen :
window.addEventListener('resize', yourfunc)
Tested under Windows 10, it works like a charm with Chrome. Worth to say that the actual screen size computed by the browser use either the screen resolution and the zoom.
For instance, if you're on 1920x1080, zoom 100% :
Passing to 3840x2160, zoom 200% will output a browser window of 1920x1080 and resize seems not triggered
Passing to zoom 150% will output a browser window of 1280x720 and resize is triggered
Nevertheless, there's a pitfall. Screen resolution update will only be detected if it actually triggers a browser window resize. That is not so obvious given the windowed/fullscreen initial state of the browser window and the smaller/bigger screen size evolution.

event is undefined for firefox browser on calling oncontextmenu

I am displaying context menu on right-clicking a button in a page. The code used for displaying context menu is
window.addEventListener('contextmenu',function (e){e.preventDefault();},false);}
When I am right clicking the button, the context menu method called is
displaycontextmenu(obj,event)
{
console.log("Context");
console.log(event);
// Displaying context menu
}
The code executes fine in IE browser, even in chrome I can see in console that "Context" and event is printed. But in firefox , it is printing as "Context" and undefined.
I am really confused to see here that the event is undefined.
I am using the event to get the x and y co-ordinates to display the context menu at right place. Since the event is undefined, am not able to proceed further.
The reason why you can see the event show up in the console of chrome and IE is that IE has always had the bad habbit of assigning the event object to a global reference (window.event).
Chrome has implemented the W3C model correctly, and passes the event object to the handler as you'd expect, but also keeps a global reference to that event object ready, just in case.
Try logging obj, it'll log the event object in FF... I'm fairly confident of that. Chrome will behave in exactly the same manner, too: the event object will be passed to the handler.
Since the event parameter is left undefined, I can only assume that event is either ignored (treated as a reserved keyword, but only quietly), or there is some behind-the-scenes scope-scanning going on that resolves the local event to the global [window.]event.
At any rate, using varnames that might be keywords, or that already exist (like document, window or this) is either not allowed or frowned upon. That's why you'll often see this:
function eventHandler (e)
{
e = e || event;
}
e is allowed as a varname, and there is no name conflict, unless we ourselves create one. if the handler didn't receive an event object, we reference event which, thanks to scope scanning, will be resolved to window.event.

IE9 iframe window removed after will can't execute code from a freed script?

In my application I created an iframe in my lightbox, when I open the lightbox after it will call parent window function and close the lightbox, in the parent window function will create and update some DOMs, and then When I go to back the parent window I try to access those DOMs it will throw an exception "script5011: Can't execute code from a freed script".
I call the parent window function at the iframe like this window.parent.myFunc(arg1, arg2....), it will got an exception, I think that is an IE 9 new feature changed, because I tested in IE 6, 7, 8 and other browsers are working fine all, I not yet find a valid solution for IE 9, I hope can get an answer from here. any ideas?
The cause of this issue is that IE9 removes reference to a parent window’s object when the frame’s URL is changed subsequently and this is done to increase security.
The solution for this is to setup functions in the parent window which can modify (setters & getters) the parent window data objects. You can pass objects to the parent window's function after its serialized to a string. The best way to call the parent frame's function is by calling the following in the child frame.
window.parent.eval("resetDataObject()");
and in the parent frame write something like:
var myDataObject = [];
function resetDataObject()
{
myDataObject = [];
}
Check this post http://www.tejzpr.com/2014/10/codefix-script5011-cant-execute-code.html

Does popup exist? (javascript)

I'm trying to determine whether a popup exists in javascript. I do know its name (passed in window.open()), but I do not have a window reference. For example consider this: I have a web page A which calls window.open('url', 'popup') and I have web page B which also wants to call window.open('url', 'popup') unless such popup exists. In this case B just focuses on popup. So web page B has no reference to popup (and it cannot have, we may assume that A and B are independent). Is there a way to do that?
You should be able to do it if you play around with your window structure.
Whenever I've come across this problem I've had a main window which always exists. Then, when calling window.open, I grab the handler that that function returns and then assign it to the main window that I know will always exist.
Then, whenever calling window.open, I go off and check main window to see if it has an open window handler for the popup window.
So, assuming you have that main window that always exists (you could always use have a window that uses a frame to display your actual content so, to your users, it'll look the same), you could do something like:
var mainWindow = window;
while(mainWindow != mainWindow.parent){
mainWindow = mainWindow.parent;
}
if(mainWindow.PopupWindow === undefined || mainWindow.PopupWindow.closed){
var handler = window.open('url', 'popup');
mainWindow.PopupWindow = handler;
}
I've always had a few problems using the closed property of the window object, so you may need to map a function to the onunload event within the popup window that just clears out the PopupWindow variable on the mainWindow, and then add that check within your if statement too.

Categories

Resources