How can we reassociate the existing page object with a new browser after closing its browser - page-object-gem

Sometimes the browser gets stuck and does not respond (this is reported to be a known issue with the refresh operation on Firefox)
In these cases, I can still proceed by doing a browser.close and re-opening a new browser.
The problem is that the current page object still points to the old browser. Is there any way to recreate the browser of an existing page object without destroying and recreating the whole page object?

The underlying browser is stored in the page object's #browser variable. This variable normally gets set by the initialize_browser method. In theory, you could call that:
# An existing page object instance
page = MyPage.new(browser)
# A new browser
browser2 = Watir::Browser.new
# Change the browser in the page object instance
page.initialize_browser(browser2)
Unless you are setting other instance variables in the page object instance, I do not believe this is going to much more beneficial than just re-initializing a page object instance (ie doing another page = MyPage.new(browser2)).

Related

Opening a new window/tab without changing focus (Chrome)?

I have a problem with focusing between browser windows/tabs. I would be very grateful for some input! :-)
Our main target browser is Chrome. And I know that the rules for what's allowed has changed over the years - because these features have been constantly abused... I've looked at a lot of older answers, e.g. I need to open a new window in the background with JavaScript, and make sure the original is still focused, but I haven't found anything that will work today. (Apparently this is called a "pop-under" window.)
In our application, in window-A, we want to open another window/tab, window-B, with a certain URL. But the focus should remain on window-A. We have full control of the webpages that are loaded in both windows, and they are loaded from the same domain.
This won't work (in window-A):
window.open('mydomain.com/second-page');
window.focus();
And this won't work (in window-B, after load):
window.opener.focus();
For a number of years now, Chrome hasn't allowed a window to set focus to itself or its parent.
This will actually work:
// in window-A:
window.name = 'HOWDY';
window.open('mydomain.com/second-page');
// in window-B:
window.open('', 'HOWDY');
Opening a blank URL in a named windows, will switch focus to that window - without changing the contents of the target window.
BUT it only works if I put it in an event handler - e.g.:
document.getElementById('mybutton').addEventListener('click', function(e) {
window.open('', 'HOWDY');
});
If I try to do it automatically (after load, or by sending the page a SignalR message), the open-blank-URL-in-named-window trick won't change focus. I suppose it's one of those "only allowed in direct response to user interaction" things. (It will load another page in window-A if I add a URL, though, so the open() call works. But window-B retains focus.)
Is there any way to solve this? Either by not moving focus to window-B in the first place, or by automatically moving focus back from window-B to window-A?
/Anders from Sweden

Why would links in an object or iframe (I've tried both) start opening in a new window

I'm working on an application that has many links. They all open in the same window, until today. All of a sudden, in all browsers I'm testing in, 3 links in an iframe or object (I've tried both) start opening in a new window. I can't seem to stop this.
An object example follows. The dolnks program generates 3 simple links like the one following the object example and these links open in a new window.
<OBJECT ID='fixed' DATA='dolnks.cgi?str=$params' TARGET='dynamic' NORESIZE></OBJECT>
darea.cgi?str=$dogstr
Can someone help me understand this and how to get these links to open in the same window.
All links that now open in the same window or should be opening in the same window are from
the same domain.
I now have to close the link instead of using the back button.
Thanks,
craigt
I imagine it's because of your TARGET attribute, although it's not using one of the special target values:
target
Where to display the linked URL, as the name for a browsing context (a tab, window, or ). The following keywords have special meanings for where to load the URL:
_self: the current browsing context. (Default)
_blank: usually a new tab, but users can configure browsers to open a new window instead.
_parent: the parent browsing context of the current one. If no parent, behaves as _self.
_top: the topmost browsing context (the "highest" context that’s an ancestor of the current one). If no ancestors, behaves as _self.
From the MDN Docs: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attributes
Note though that the docs for object do not list a target attribute, so that behavior is apparently undefined, and probably varies depending on the browser, and the plugin displaying the object.
Check to see if it's the items with a target attribute (case does not matter) that are working "wrong", and see if removing that attribute fixes it. If that's not it, next check to see if there are javascript being loaded. Try turning javascript off (hopefully the relevant links are not generated with javascript) and see if that fixes the behavior. If turning javascript off is too heavy handed, you can use the javascript console to see what listeners are attached to the links.

If I load content dynamically, does history.pushState() cause that content to be added to the browser cache?

Here's what happens:
Page loads (a timeline view)
User scrolls down to the bottom
More timeline content is loaded via AJAX
The URL is set to a new value with history.pushState(). If this URL is accessed directly, it loads the timeline so that it includes all content that's been loaded dynamically so far.
The user clicks a link in the timeline
The user then clicks the back button in the browser.
My question: when the back button is pressed, will the browser do a fresh load of the url provided via pushState() (which may involve a large performance hit if they have gone a long way down the timeline)? I'm hoping that instead it will update its page cache somehow when pushState() is called to include the DOM with the dynamic content added, and then reload that instead.
If it doesn't do any automatic cache magic like that, is there any way to make it do so in order to improve performance? It seems wasteful to reload a large number of posts every time the user clicks away from the timeline. Also, as they scroll, the URL is constantly updated so it would be a fresh load of all posts every time they click away, not even using normal browser caching.
I've looked for information, but can't seem to find anything that says how pushState() modifies the cache, if at all.

Chrome Extension Local Storage: Background.html doesn't have access to localstorage?

Writing and reading from LocalStorage is working fine from my popup and tab. However, when I attempt to add a value from my background page, it doesn't seem to write at all. I'm viewing local storage in Chrome Developer Tools by refreshing and looking for the value to show.
In the following example code for background.html 'lastId' is displayed correctly in the alert when a new bookmark is added. However, the value is not stored. Additionally, the request for a known value appears to fail with no alert displaying. (Results are the same attempting both syntaxes shown below.)
<html>
<script>
// Grab the id of newly created bookmarks
chrome.bookmarks.onCreated.addListener(function(id) {
var lastId = id;
alert(lastId);
localStorage['lastId'] = lastId;
var testvalue = localStorage['309'];
alert(testvalue);
localStorage.setItem('lastId', lastId);
var testvalue2 = localStorage.getItem('309');
alert(testvalue2);
});
</script>
</html>
I keep thinking I must just be missing some small syntax issue or something but can't see anything. If my manifest declaration was incorrect I don't think the alert would work for the id. Stumped...
UPDATE: Turns out that you have to force reload of the extension on updates to background pages since they are persistent in browser memory when opened. That is why my saved code appeared not to work. It wasn't refreshed and I am duly embarrassed.
Hm, I can think about couple things.
You say that it works in a tab and a popup. This is very strange because it shouldn't (if by tab you mean content script). Content scripts are able to access only localStorage that belongs to a site they are injected. Popup, background, option pages, and any othe page from extension's folder can only access extension's own localStorage. Those two local storages and completely separated. So maybe you are inspecting wrong localStorage?
To see extension's own localStorage you need to inspect background or popup page and check resources tab in the inspector. To inspect site or content script localStorage you need to open regular inspector on the page.
Second moment is your localStorage assignment might be not what you are expecting.
If you run:
var lastId = 5;
localStorage['lastId'] = lastId;
you will get value 5 assigned to lastId property. So to read written value you need to run:
alert(localStorage['lastId']); //not localStorage['5']
If you want to store arrays then you would need to serialize/unserialize them through JSON as localStorage can store only strings.

Is swapCache() required in HTML5 offline apps?

If I don't implement any updateready event handler and don't call swapCache(), does that mean that the browser will always use the first (oldest) downloaded version of the application?
If no, then why is the swapCache() method needed?
Swapcache makes sure that "subsequent" calls to cached resources are taken from the new cache.
Subsequent meaning after swapcache.
To see this in action try setting the src property of an img dynamically after the
swapcache call in the updateready event (so that the browser loads it at that particular
time). Make sure this image is not already loaded elsewhere in the page since that will
distort this test.
Now change the image and change the manifest files (to force reloading the cached files).
Reload the page in your browser.
You should now see the new version of the image in your rendered page.
Now comment out the call to swapcache.
Make a change to the manifest file and reload the page and thus all resources.
Refresh the page again (to make sure you have a version from the new cache).
Now change the image again and change the manifest.
Again reload the page: now you see the old version of the image.
In the last case, the browser finished loading the new versions in cache, but since
swapcache was not called, the image was still taken from the old cache.
If you do not do any dynamic loading of resources in your page, the swapcache has no effect.
In particular, if you reload the page in the updateready event handler calling swapcache
first has no effect since reloading the page will get it from the new cache anyway.
I have an app with a pretty large cache (>100mb). This takes a particularly long time to swap the cache in (and pretty much locks the browser while this is happening). So I display a message indicating that the app is updating (please wait...), then call swapCache(), then display a new message when it's done indicating completion.
Not sure if this answers your question (as to why it's necessarily needed), but I think it provides a valid use case for swapCache() at least.
Let's imagine 2 different scenarios.
You call location.reload() when the new content is available. The page will reload using its all-new content. applicationCache.swapCache() is not needed in this case.
Your user continues to interact with your page, without any reload. This interaction causes an asset to load dynamically. For the sake of argument, let's imagine that it's a rollover image, and let's imagine that you have just updated this rollover image. Without applicationCache.swapCache(), your user will continue to see the old rollover image. After applicationCache.swapCache(), s/he will see the new rollover image.
So applicationCache.swapCache() without a reload says: "Keep the page looking the way it was when it was loaded, but use any new assets now, as soon as the page asks for them".
The SwapCache method provides a mechanism for the application to be in control of how an when updates are applied. In regular HTML apps, it can be difficult to determine if the correct JS is present on the clients browser.
Also browser implementations vary on when a cache would be updated, I found the iPhone particularly stubborn. swapCache put me back in control of how my app is updated i.e. I could choose to automatically apply the patch or let the user choose when to apply etc.
I was wondering the same thing. I seem to be able to trigger a successful update by just calling "window.applicationCache.update()". If the manifest file has been modified, the 'download' event is triggered, then eventually the "update ready".
When I reload it, it appears to have been applied. I don't seem to need to call swapCache(). I have provision for calling it from the app, but so far have not noticed any effect on the update process.
Calling update() basically eliminates one reload, AFAICS.
swapCache will switch from the previous set of resources listed in the cache manifest (when the running webapp was loaded) to the new set. You are doing this in response to an updateready after all, which signals that a new manifest has been loaded.
This is not to be confused with loading individual resources, for which the usual browser caching policies still apply. In other words you will swap set of resources, but individual resources need their own cache management to ensure they're reloaded when you need them to.
I haven't tried this yet, but it would seem to suggest structuring the code as an "update controller" javascript file that handles the update process, and javascript sources with a versioned filename (or URL) with known entry points.