How to check broken links in a webpage using Casperjs? - javascript

I want to check all broken links present in a webpage using casperjs. I write following code but it not working:
casper.then(function() {
var urls=casper.getElementsAttribute('a[href]', 'href');
casper.eachThen(urls, function(response) {
var link=response.data;
this.thenOpen(demourl, function(response) {
if (response == undefined || response.status >= 400) {
this.echo("failed");
}
})
this.on('http.status.404', function(resource) {
this.echo('wait, this url is 404: ' + resource.url);
})
})
})
My Webpage consists of more than 400 links. My code doesn't complete its execution and remains idle after some links. It is not giving me any response. I am not getting why this happening?

Get link URLs
There is a difference between attributes and properties of DOM elements. If you have a website which is on the domain http://example.com and you want to get the href of the following link on that page
text
If you use aElement.getAttribute("href") you will get "/path/to/stuff", but if you use aElement.href, you will get the computed URL "http://example.com/path/to/stuff". Only the latter is a URL that CasperJS (actually PhantomJS) understands.
I'm telling you this, because casper.getElementsAttribute() internally uses the element.getAttribute() approach which produces URLs that cannot be opened with casper.thenOpen().
The fix is easy:
var urls = casper.evaluate(function(){
return [].map.call(document.querySelectorAll('a[href]'), function(a){
return a.href;
});
});
Also, you might want to move the casper.on() event registration above the casper.eachThen() call. You don't need to register the event in every iteration.
Registering link timeouts
Since you have problems with some URLs not loading (probably because they are broken), you can use casper.options.stepTimeout to set a timeout for steps, so that CasperJS won't freeze on some unretrievable URL. You also need to define the onStepTimeout() callback, otherwise CasperJS will exit.
casper.then(function() {
var currentURL;
casper.options.stepTimeout = 10000; // 10 seconds
casper.options.onStepTimeout = function(timeout, stepNum){
this.echo('wait, this url timed out: ' + currentURL);
};
var urls = this.evaluate(function(){
return [].map.call(document.querySelectorAll('a[href]'), function(a){
return a.href;
});
});
this.on('http.status.404', function(resource) {
this.echo('wait, this url is 404: ' + resource.url);
});
urls.forEach(function(link) {
this.then(function(){
currentURL = link;
});
this.thenOpen(link, function(response) {
if (response == undefined || response.status >= 400) {
this.echo("failed: " + link);
}
});
});
});

Related

infinite scroll on squarespace get category filter

I am using this code to infinite load a page on squarespace. My problem is the reloading doesn't capture the filtering that I have set up in my url. It cannot seem to 'see' the variables or even the url or categoryFilter in my collection. I've tried to use a .var directive but the lazy loaded items cannot see the scope of things defined before it. I'm running out of ideas here please help!
edit: I've since found the answer but gained another question.
I was able to use window.location.href instead of window.location.pathname to eventually get the parameters that way. Except this doesn't work in IE11 so now I have to search for this.
<script>
function infiniteScroll(parent, post) {
// Set some variables. We'll use all these later.
var postIndex = 1,
execute = true,
stuffBottom = Y.one(parent).get('clientHeight') + Y.one(parent).getY(),
urlQuery = window.location.pathname,
postNumber = Static.SQUARESPACE_CONTEXT.collection.itemCount,
presentNumber = Y.all(post).size();
Y.on('scroll', function() {
if (presentNumber >= postNumber && execute === true) {
Y.one(parent).append('<h1>There are no more posts.</h1>')
execute = false;
} else {
// A few more variables.
var spaceHeight = document.documentElement.clientHeight + window.scrollY,
next = false;
/*
This if statement measures if the distance from
the top of the page to the bottom of the content
is less than the scrollY position. If it is,
it's sets next to true.
*/
if (stuffBottom < spaceHeight && execute === true) {
next = true;
}
if (next === true) {
/*
Immediately set execute back to false.
This prevents the scroll listener from
firing too often.
*/
execute = false;
// Increment the post index.
postIndex++;
// Make the Ajax request.
Y.io(urlQuery + '?page=' + postIndex, {
on: {
success: function (x, o) {
try {
d = Y.DOM.create(o.responseText);
} catch (e) {
console.log("JSON Parse failed!");
return;
}
// Append the contents of the next page to this page.
Y.one(parent).append(Y.Selector.query(parent, d, true).innerHTML);
// Reset some variables.
stuffBottom = Y.one(parent).get('clientHeight') + Y.one(parent).getY();
presentNumber = Y.all(post).size();
execute = true;
}
}
});
}
}
});
}
// Call the function on domready.
Y.use('node', function() {
Y.on('domready', function() {
infiniteScroll('#content','.lazy-post');
});
});
</script>
I was able to get this script working the way I wanted.
I thought I could use:
Static.SQUARESPACE_CONTEXT.collection.itemCount
to get {collection.categoryFilter} like with jsont, like this:
Static.SQUARESPACE_CONTEXT.collection.categoryFilter
or this:
Static.SQUARESPACE_CONTEXT.categoryFilter
It didn't work so I instead changed
urlQuery = window.location.pathname
to
urlQuery = window.location.href
which gave me the parameters I needed.
The IE11 problem I encountered was this script uses
window.scrollY
I changed it to the ie11 compatible
Window.pageYOffset
and we were good to go!

Automating Facebook group post deletion using CasperJS

I'm working on writing a script to delete posts from a Facebook Group, since Facebook's Graph API won't allow a developer to do so unless the posts were made from the developer's account.
So far, I have been able to log into Facebook, then navigate to the desired group page. From there I can get the XPath for each post visible on the page (using the selector a[data-testid='post_chevron_button']). My script fails while trying to call this.click() on each XPath selector.
My current script is as follows:
phantom.casperTest = true;
var x = require('casper').selectXPath;
var casper = require('casper').create({
verbose: true,
pageSettings: {
loadImages: false,
loadPlugins: false,
userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4'
}
});
// print out all the messages in the headless browser context
casper.on('remote.message', function(msg) {
this.echo('remote message caught: ' + msg);
});
// print out all the messages in the headless browser context
casper.on("page.error", function(msg, trace) {
this.echo("Page Error: " + msg, "ERROR");
});
var url = 'http://www.facebook.com/';
casper.start(url, function() {
console.log("page loaded");
this.test.assertExists('form#login_form', 'form is found');
this.fill('form#login_form', {
email: '{email}',
pass: '{password}'
}, true);
this.click('#u_0_q');
this.wait(1000, function() {
this.echo("Capturing image of page after login.");
this.capture('loggedin.png');
});
});
casper.thenOpen('https://www.facebook.com/groups/{group-id}/', function() {
this.echo(this.getTitle());
this.wait(1000, function() {
this.capture('group.png');
});
var elements = casper.getElementsInfo("a[data-testid='post_chevron_button']");
var index = 1;
elements.forEach(function(element){
var xpath = '//*[#id="' + element.attributes["id"] + '"]';
console.log(xpath);
this.click(x(xpath));
this.wait(100, function() {
this.capture('chevronlink' + index + '.png');
});
index++;
});
});
casper.run();
When the script gets to this.click(x(xpath)); I get the error message TypeError: undefined is not a constructor (evaluating 'this.click(x(xpath))'). If I simply replace the last bit of code that creates an array and iterates through it with this.click("a[data-testid='post_chevron_button']");, my script has no problem.
Does anyone know what CasperJS doesn't like about calling click() with the XPath selector? XPath appears to be a valid selector going off of CasperJS's docs.
UPDATE
I've updated the title of the question to more accurately describe the desired result.
Per dasmelch's advice, I've reworked the script a bit and incorporated this bit into the script instead (after the casper.thenOpen portion):
casper.then(function() {
var elements = casper.getElementsAttribute("a[data-
testid='post_chevron_button']", 'id');
while (elements.length > 0) {
// get always the last element with target id
element = elements.pop();
(function(element) {
var xpath = '//*[#id="' + element + '"]';
console.log(xpath);
// do it step by step
casper.then(function() {
this.click(x(xpath));
});
casper.then(function() {
this.capture('chevronlink' + element + '.png');
});
// go back to the page with the links (if necessary)
casper.then(function() {
casper.back();
});
})(element);
};
});
I now get this error: Cannot dispatch mousedown event on nonexistent selector: xpath selector: //*[#id="u_0_47"].
Last night, I decided to go about it a little differently. I got closer to the desired end result, but now CasperJS and/or PhantomJS is having trouble finding the elements that are present in the dropdown after clicking the post_chevron_button. Here is what I ended up with (everything prior to casper.thenOpen remains the same in the script shown originally):
casper.thenOpen('https://www.facebook.com/groups/{group-id}/', function() {
this.echo(this.getTitle());
this.wait(1000, function() {
this.capture('group.png');
});
var elements = casper.getElementsInfo("a[data-
testid='post_chevron_button']");
while (elements.length > 0) {
this.click("a[data-testid='post_chevron_button']");
this.wait(1000, function() {
this.capture('chevron_click.png');
console.log("chevron_click.png saved");
});
var chevronLinks = casper.getElementsInfo("a[ajaxify]")
console.log("Found " + chevronLinks.length + " elements with ajaxify attribute.");
var chevronLinksIndex = 1;
chevronLinks.forEach(function(element){
var ajaxifyValue = element.attributes["ajaxify"];
console.log(ajaxifyValue);
if (ajaxifyValue.indexOf("delete.php?group_id={group-id}") !== -1) {
this.click("a[ajaxify='"+ajaxifyValue+"']");
this.wait(100, function(){
this.capture('deletePost' + chevronLinksIndex);
});
chevronLinksIndex++;
}
});
if (chevronLinksIndex === 1) {
break;
}
elements = casper.getElementsInfo("a[data-testid='post_chevron_button']");
}
});
I know there should be an element that contains an ajaxify attribute with the value I'm searching for (because stepping through it in a browser myself shows the element after the click on a[data-testid='post_chevron_button']), but Casper cannot find it. Not only that, my chevron_click.png image file should be updating on each run of this script, but it's not.
Some of the code execution is not happening in order. For instance, the logging of ajaxify attribute values is happening in the console prior to seeing chevron_click.png saved. This may be expected, but unfortunately I don't have a lot of JS experience. This execution order problem may explain why my search for the necessary element is not returning what I expect.
Here is an example of the element needing clicked for deletion of a post:
<a class="_54nc" href="#" rel="async-post"
ajaxify="/ajax/groups/mall/delete.php?group_id={group-id}&message_id=806608486110204&story_dom_id=mall_post_806608486110204%3A6%3A0&entstory_context=%7B%22last_view_time%22%3A1495072771%2C%22fbfeed_context%22%3Atrue%2C%22location_type%22%3A2%2C%22outer_object_element_id%22%3A%22mall_post_806608486110204%3A6%3A0%22%2C%22object_element_id%22%3A%22mall_post_806608486110204%3A6%3A0%22%2C%22is_ad_preview%22%3Afalse%2C%22is_editable%22%3Afalse%2C%22mall_how_many_post_comments%22%3A2%2C%22bump_reason%22%3A0%2C%22story_width%22%3A502%2C%22shimparams%22%3A%7B%22page_type%22%3A16%2C%22actor_id%22%3A664025626%2C%22story_id%22%3A806608486110204%2C%22ad_id%22%3A0%2C%22_ft_%22%3A%22%22%2C%22location%22%3A%22group%22%7D%2C%22story_id%22%3A%22u_0_21%22%2C%22caret_id%22%3A%22u_0_22%22%7D&surface=group_post_chevron"
role="menuitem"><span><span class="_54nh"><div class="_41t5"><i
class="_41t7 img sp_gJvT8CoKHU- sx_0f12ae"></i><i class="_41t8 img
sp_s36yWP_7MD_ sx_7e9f7d"></i>Delete Post</div></span></span></a>
I was able to accomplish what I was trying to do with the Selenium 2 API for .NET.
The solution code is below:
class Program
{
static void Main(string[] args)
{
var options = new ChromeOptions();
options.AddUserProfilePreference("profile.default_content_setting_values.notifications", 2);
using (IWebDriver driver = new ChromeDriver(options))
{
// Maximize window
driver.Manage().Window.Maximize();
// Log into Facebook
driver.Navigate().GoToUrl("http://www.facebook.com/");
driver.FindElement(By.Id("email")).SendKeys("username");
driver.FindElement(By.Id("pass")).SendKeys("password");
driver.FindElement(By.Id("pass")).SendKeys(Keys.Enter);
driver.Navigate().GoToUrl("https://www.facebook.com/groups/{group-id}/");
var chevronPostLinks = driver.FindElements(By.XPath("//a[#data-testid='post_chevron_button']"));
chevronPostLinks.FirstOrDefault().Click();
Thread.Sleep(1000);
var deletePostElements = driver.FindElements(By.XPath("//a[contains(#ajaxify,'delete.php?group_id={group-id}')]"));
while (deletePostElements.Count > 0 && chevronPostLinks.Count > 0)
{
Thread.Sleep(1000);
deletePostElements.Where(x => x.Displayed == true).FirstOrDefault().Click();
Thread.Sleep(1000);
driver.FindElement(By.ClassName("layerConfirm")).Click();
Thread.Sleep(2000);
chevronPostLinks = driver.FindElements(By.XPath("//a[#data-testid='post_chevron_button']"));
if (chevronPostLinks.Count > 0)
{
chevronPostLinks.FirstOrDefault().Click();
}
else
{
driver.Navigate().GoToUrl("https://www.facebook.com/groups/{group-id}/");
chevronPostLinks = driver.FindElements(By.XPath("//a[#data-testid='post_chevron_button']"));
chevronPostLinks.FirstOrDefault().Click();
}
Thread.Sleep(1000);
deletePostElements = driver.FindElements(By.XPath("//a[contains(#ajaxify,'delete.php?group_id={group-id}')]"));
}
}
}
}
There are some improvements I'd like to make, like using Selenium to wait for elements to be visible instead of using Thread.Sleep(), but it's working just fine for my purpose.
You do the xpath stuff correct, but it seems the method forEach is not working for this.
You can grab directly the id of all these elements with casper.getElementsAttribute an iterate easy with a while loop throw that them more easily like that:
...
casper.thenOpen('https://www.facebook.com/groups/{group-id}/', function() {
this.echo(this.getTitle());
this.wait(1000, function() {
this.capture('group.png');
});
});
// do a while loop with where you can use every single element and jump back
casper.then(function() {
var elements = casper.getElementsAttribute("a[data-testid='post_chevron_button']", 'id');
while (elements.length > 0) {
// get always the last element with target id
element = elements.pop();
(function(element) {
var xpath = '//*[#id="' + element + '"]';
console.log(xpath);
// do it step by step
casper.then(function() {
this.click(x(xpath));
});
casper.then(function() {
this.capture('chevronlink' + element + '.png');
});
// go back to the page with the links (if necessary)
casper.then(function() {
casper.back();
});
})(element);
};
});
...
Without looking at FB, i guess you have to go back (casper.back) to the site where the links (elements) are.

If iframe refresh failed, then X

I'm using the following script to refresh my <iframe> every 60 seconds.
<script type=text/javascript>
setInterval(function() {
document.getElementById("tracker").src += "";
}, 60000);
</script>
I would like to show a different page/<iframe> if the refresh fails. For example, if I'm not connected to any network, then obviously any page refresh will show the "page not found" error.
Instead, I would like to display a different <iframe> (e.g. tracker2) or different page/message/image to say "Offline". Of course the <iframe> will keep refreshing itself until there's internet connection.
I'm pretty sure that's not possible, however I may be wrong. Is it possible?
If the <iframe> you're loading is on a different domain, then no, it's not possible. Otherwise, you can use Ajax to check the status:
var rq = new XMLHttpRequest();
rq.open('GET', document.getElementById('tracker').src, true);
rq.onreadystatechange = function() {
if(rq.readyState === 4) {
if(rq.status === 200) {
// All is well
} else {
// Show your backup element
}
}
};
rq.send(null);
You can check http code of your iframe and depending on that you can render another page
You can use Jquery ajax to load page content and check page status. For example:
<script type=text/javascript>
setInterval(loadIframe, 60000);
function loadIframe()
{
$.ajax({
type: 'GET',
url: 'document.getElementById('tracker').src',
success: function(data){
alert('horray! 200 status code!');
document.getElementById("tracker").src += "";
},
error: function(data){
//get the status code
if (code == 400) {
alert('400 status code! user error');
}
if (code == 500) {
alert('500 status code! server error');
}
},
});
}
</script>

Override "Error Loading Page" for network failure in js file

I have JQuery Mobile-1.0.js file.
// Load a page into the DOM.
$.mobile.loadPage = function (url, options) {
// This function uses deferred notifications to let callers
// know when the page is done loading, or if an error has occurred.
var deferred = $.Deferred(),
// The default loadPage options with overrides specified by
// the caller.
settings = $.extend({}, $.mobile.loadPage.defaults, options),
// The DOM element for the page after it has been loaded.
page = null,
// If the reloadPage option is true, and the page is already
// in the DOM, dupCachedPage will be set to the page element
// so that it can be removed after the new version of the
// page is loaded off the network.
dupCachedPage = null,
// determine the current base url
findBaseWithDefault = function () {
var closestBase = ($.mobile.activePage && getClosestBaseUrl($.mobile.activePage));
return closestBase || documentBase.hrefNoHash;
},
// The absolute version of the URL passed into the function. This
// version of the URL may contain dialog/subpage params in it.
absUrl = path.makeUrlAbsolute(url, findBaseWithDefault());
// If the caller provided data, and we're using "get" request,
// append the data to the URL.
if (settings.data && settings.type === "get") {
absUrl = path.addSearchParams(absUrl, settings.data);
settings.data = undefined;
}
// If the caller is using a "post" request, reloadPage must be true
if (settings.data && settings.type === "post") {
settings.reloadPage = true;
}
// The absolute version of the URL minus any dialog/subpage params.
// In otherwords the real URL of the page to be loaded.
var fileUrl = path.getFilePath(absUrl),
// The version of the Url actually stored in the data-url attribute of
// the page. For embedded pages, it is just the id of the page. For pages
// within the same domain as the document base, it is the site relative
// path. For cross-domain pages (Phone Gap only) the entire absolute Url
// used to load the page.
dataUrl = path.convertUrlToDataUrl(absUrl);
// Make sure we have a pageContainer to work with.
settings.pageContainer = settings.pageContainer || $.mobile.pageContainer;
// Check to see if the page already exists in the DOM.
page = settings.pageContainer.children(":jqmData(url='" + dataUrl + "')");
// If we failed to find the page, check to see if the url is a
// reference to an embedded page. If so, it may have been dynamically
// injected by a developer, in which case it would be lacking a data-url
// attribute and in need of enhancement.
if (page.length === 0 && dataUrl && !path.isPath(dataUrl)) {
page = settings.pageContainer.children("#" + dataUrl)
.attr("data-" + $.mobile.ns + "url", dataUrl);
}
// If we failed to find a page in the DOM, check the URL to see if it
// refers to the first page in the application. If it isn't a reference
// to the first page and refers to non-existent embedded page, error out.
if (page.length === 0) {
if ($.mobile.firstPage && path.isFirstPageUrl(fileUrl)) {
// Check to make sure our cached-first-page is actually
// in the DOM. Some user deployed apps are pruning the first
// page from the DOM for various reasons, we check for this
// case here because we don't want a first-page with an id
// falling through to the non-existent embedded page error
// case. If the first-page is not in the DOM, then we let
// things fall through to the ajax loading code below so
// that it gets reloaded.
if ($.mobile.firstPage.parent().length) {
page = $($.mobile.firstPage);
}
} else if (path.isEmbeddedPage(fileUrl)) {
deferred.reject(absUrl, options);
return deferred.promise();
}
}
// Reset base to the default document base.
if (base) {
base.reset();
}
// If the page we are interested in is already in the DOM,
// and the caller did not indicate that we should force a
// reload of the file, we are done. Otherwise, track the
// existing page as a duplicated.
if (page.length) {
if (!settings.reloadPage) {
enhancePage(page, settings.role);
deferred.resolve(absUrl, options, page);
return deferred.promise();
}
dupCachedPage = page;
}
var mpc = settings.pageContainer,
pblEvent = new $.Event("pagebeforeload"),
triggerData = { url: url, absUrl: absUrl, dataUrl: dataUrl, deferred: deferred, options: settings };
// Let listeners know we're about to load a page.
mpc.trigger(pblEvent, triggerData);
// If the default behavior is prevented, stop here!
if (pblEvent.isDefaultPrevented()) {
return deferred.promise();
}
if (settings.showLoadMsg) {
// This configurable timeout allows cached pages a brief delay to load without showing a message
var loadMsgDelay = setTimeout(function () {
$.mobile.showPageLoadingMsg();
}, settings.loadMsgDelay),
// Shared logic for clearing timeout and removing message.
hideMsg = function () {
// Stop message show timer
clearTimeout(loadMsgDelay);
// Hide loading message
$.mobile.hidePageLoadingMsg();
};
}
if (!($.mobile.allowCrossDomainPages || path.isSameDomain(documentUrl, absUrl))) {
deferred.reject(absUrl, options);
} else {
// Load the new page.
$.ajax({
url: fileUrl,
type: settings.type,
data: settings.data,
dataType: "html",
success: function (html, textStatus, xhr) {
//pre-parse html to check for a data-url,
//use it as the new fileUrl, base path, etc
var all = $("<div></div>"),
//page title regexp
newPageTitle = html.match(/<title[^>]*>([^<]*)/) && RegExp.$1,
// TODO handle dialogs again
pageElemRegex = new RegExp("(<[^>]+\\bdata-" + $.mobile.ns + "role=[\"']?page[\"']?[^>]*>)"),
dataUrlRegex = new RegExp("\\bdata-" + $.mobile.ns + "url=[\"']?([^\"'>]*)[\"']?");
// data-url must be provided for the base tag so resource requests can be directed to the
// correct url. loading into a temprorary element makes these requests immediately
if (pageElemRegex.test(html)
&& RegExp.$1
&& dataUrlRegex.test(RegExp.$1)
&& RegExp.$1) {
url = fileUrl = path.getFilePath(RegExp.$1);
}
if (base) {
base.set(fileUrl);
}
//workaround to allow scripts to execute when included in page divs
all.get(0).innerHTML = html;
page = all.find(":jqmData(role='page'), :jqmData(role='dialog')").first();
//if page elem couldn't be found, create one and insert the body element's contents
if (!page.length) {
page = $("<div data-" + $.mobile.ns + "role='page'>" + html.split(/<\/?body[^>]*>/gmi)[1] + "</div>");
}
if (newPageTitle && !page.jqmData("title")) {
if (~newPageTitle.indexOf("&")) {
newPageTitle = $("<div>" + newPageTitle + "</div>").text();
}
page.jqmData("title", newPageTitle);
}
//rewrite src and href attrs to use a base url
if (!$.support.dynamicBaseTag) {
var newPath = path.get(fileUrl);
page.find("[src], link[href], a[rel='external'], :jqmData(ajax='false'), a[target]").each(function () {
var thisAttr = $(this).is('[href]') ? 'href' :
$(this).is('[src]') ? 'src' : 'action',
thisUrl = $(this).attr(thisAttr);
// XXX_jblas: We need to fix this so that it removes the document
// base URL, and then prepends with the new page URL.
//if full path exists and is same, chop it - helps IE out
thisUrl = thisUrl.replace(location.protocol + '//' + location.host + location.pathname, '');
if (!/^(\w+:|#|\/)/.test(thisUrl)) {
$(this).attr(thisAttr, newPath + thisUrl);
}
});
}
//append to page and enhance
// TODO taging a page with external to make sure that embedded pages aren't removed
// by the various page handling code is bad. Having page handling code in many
// places is bad. Solutions post 1.0
page
.attr("data-" + $.mobile.ns + "url", path.convertUrlToDataUrl(fileUrl))
.attr("data-" + $.mobile.ns + "external-page", true)
.appendTo(settings.pageContainer);
// wait for page creation to leverage options defined on widget
page.one('pagecreate', $.mobile._bindPageRemove);
enhancePage(page, settings.role);
// Enhancing the page may result in new dialogs/sub pages being inserted
// into the DOM. If the original absUrl refers to a sub-page, that is the
// real page we are interested in.
if (absUrl.indexOf("&" + $.mobile.subPageUrlKey) > -1) {
page = settings.pageContainer.children(":jqmData(url='" + dataUrl + "')");
}
//bind pageHide to removePage after it's hidden, if the page options specify to do so
// Remove loading message.
if (settings.showLoadMsg) {
hideMsg();
}
// Add the page reference and xhr to our triggerData.
triggerData.xhr = xhr;
triggerData.textStatus = textStatus;
triggerData.page = page;
// Let listeners know the page loaded successfully.
settings.pageContainer.trigger("pageload", triggerData);
deferred.resolve(absUrl, options, page, dupCachedPage);
},
error: function (xhr, textStatus, errorThrown) {
//set base back to current path
if (base) {
base.set(path.get());
}
// Add error info to our triggerData.
triggerData.xhr = xhr;
triggerData.textStatus = textStatus;
triggerData.errorThrown = errorThrown;
var plfEvent = new $.Event("pageloadfailed");
// Let listeners know the page load failed.
settings.pageContainer.trigger(plfEvent, triggerData);
// If the default behavior is prevented, stop here!
// Note that it is the responsibility of the listener/handler
// that called preventDefault(), to resolve/reject the
// deferred object within the triggerData.
if (plfEvent.isDefaultPrevented()) {
return;
}
// Remove loading message.
if (settings.showLoadMsg) {
// Remove loading message.
hideMsg();
//show error message
$("<div class='ui-loader ui-overlay-shadow ui-body-e ui-corner-all'><h1>" + $.mobile.pageLoadErrorMessage + "</h1></div>")
.css({ "display": "block", "opacity": 0.96, "top": $window.scrollTop() + 100 })
.appendTo(settings.pageContainer)
.delay(800)
.fadeOut(400, function () {
$(this).remove();
});
}
deferred.reject(absUrl, options);
}
});
}
return deferred.promise();
};
This is the code for showing an error message "Error Loading Page" for error in page. Here i want to show alert message for net connection failure as "Please check your net connection" instead of the below image.
Note: I dont want to change the pageloaderrormessage. want to stop to get the page error messages, instead of that i will enable my network error condition as in Show Network Error in android. If the user pressed "Ok" in alert dialog i'll navigate them into Reload.html.
Please tell me where i can check that condition and where i have to change the error message?
As both #shkschneider and #codemonkey have suggested you need to set this option on mobileinit
Example:
$(document).bind("mobileinit", function(){
$.mobile.pageLoadErrorMessage = "Please check your net connection";
});
Linking the jQM 1.0.1 docs:
http://jquerymobile.com/demos/1.0.1/docs/api/globalconfig.html
Here is a example:
http://jquerymobile.com/demos/1.0.1/docs/config/pageLoadErrorMessage.html ( click the "or Try this broken link" button )
Now if you have the ability to upgrade jQM to 1.1.1 you might try something like this:
//use theme swatch "b", a custom message, and no spinner
$.mobile.showPageLoadingMsg("b", "Please check your net connection", true);
// hide after delay
setTimeout( $.mobile.hidePageLoadingMsg, 1500 );
Docs:
http://jquerymobile.com/demos/1.1.1/docs/api/methods.html
UPDATE:
Another thought is to use a plugin to achieve something like you want, Does something like this work?
http://dev.jtsage.com/jQM-SimpleDialog/demos/bool.html
Simply use:
$(document).bind("mobileinit", function(){
$.mobile.pageLoadErrorMessage("Please check your netconnection");
});
http://jquerymobile.com/test/docs/api/globalconfig.html
Set the pageLoadErrorMessage as described here http://jquerymobile.com/demos/1.1.1/docs/api/globalconfig.html
EDIT
If you want to handle the behaviour in a custom way, set loadingMessage to false. This prevents the loading message from being displayed. You can bind to the pageloadfailed (described here http://jquerymobile.com/demos/1.1.1/docs/api/events.html) and add add your custom handling logic in the event handler.

checking the page exist or not using javascript [duplicate]

I have a link: Hello.
When someone clicks the link I'd like to check via JavaScript if the page the href-attribute points to exists or not. If the page exists the browser redirects to that page ("www.example.com" in this example) but if the page doesn't exist the browser should redirect to another URL.
It depends on whether the page exists on the same domain or not. If you're trying to determine if a page on an external domain exists, it won't work – browser security prevents cross-domain calls (the same-origin policy).
If it is on the same domain however, you can use jQuery like Buh Buh suggested. Although I'd recommend doing a HEAD-request instead of the GET-request the default $.ajax() method does – the $.ajax() method will download the entire page. Doing a HEAD request will only return the headers and indicate whether the page exists (response codes 200 - 299) or not (response codes 400 - 499). Example:
$.ajax({
type: 'HEAD',
url: 'http://yoursite.com/page.html',
success: function() {
// page exists
},
error: function() {
// page does not exist
}
});
See also: http://api.jquery.com/jQuery.ajax/
A pretty good work around is to proxy. If you don't have access to a server side you can use YQL. Visit: http://developer.yahoo.com/yql/console/
From there you can do something like: select * from htmlstring where url="http://google.com". You can use the "REST query" they have on that page as a starting point for your code.
Here's some code that would accept a full URL and use YQL to detect if that page exists:
function isURLReal(fullyQualifiedURL) {
var URL = encodeURIComponent(fullyQualifiedURL),
dfd = $.Deferred(),
checkURLPromise = $.getJSON('http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20htmlstring%20where%20url%3D%22' + URL + '%22&format=json');
checkURLPromise
.done(function(response) {
// results should be null if the page 404s or the domain doesn't work
if (response.query.results) {
dfd.resolve(true);
} else {
dfd.reject(false);
}
})
.fail(function() {
dfd.reject('failed');
});
return dfd.promise();
}
// usage
isURLReal('http://google.com')
.done(function(result) {
// yes, or request succeded
})
.fail(function(result) {
// no, or request failed
});
Update August 2nd, 2017
It looks like Yahoo deprecated "select * from html", although "select * from htmlstring" does work.
Based on the documentation for XMLHttpRequest:
function returnStatus(req, status) {
//console.log(req);
if(status == 200) {
console.log("The url is available");
// send an event
}
else {
console.log("The url returned status code " + status);
// send a different event
}
}
function fetchStatus(address) {
var client = new XMLHttpRequest();
client.onreadystatechange = function() {
// in case of network errors this might not give reliable results
if(this.readyState == 4)
returnStatus(this, this.status);
}
client.open("HEAD", address);
client.send();
}
fetchStatus("/");
This will however only work for URLs within the same domain as the current URL. Do you want to be able to ping external services? If so, you could create a simple script on the server which does your job for you, and use javascript to call it.
If it is in the same domain, you can make a head request with the xmlhttprequest object [ajax] and check the status code.
If it is in another domain, make an xmlhttprequest to the server and have it make the call to see if it is up.
why not just create a custom 404 handler on the web server? this is probably the more "good-bear" way to do this.
$.ajax({
url: "http://something/whatever.docx",
method: "HEAD",
statusCode: {
404: function () {
alert('not found');
},
200: function() {
alert("foundfile exists");
}
}
});
If you are happy to use jQuery you could do something like this.
When the page loads make an ajax call for each link. Then just replace the href of all the links which fail.
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
<script type="text/javascript">
<!--
$.fn.checkPageExists = function(defaultUrl){
$.each(this, function(){
var $link = $(this);
$.ajax({
url: $link.attr("href"),
error: function(){
$link.attr("href", defaultUrl);
}
});
});
};
$(document).ready(function(){
$("a").checkPageExists("default.html");
});
//-->
</script>
You won't be able to use an ajax call to ping the website because of same-origin policy.
The best way to do it is to use an image and if you know the website you are calling has a favicon or some sort of icon to grab, you can just use an html image tag and use the onerror event.
Example:
function pingImgOnWebsite(url) {
var img = document.createElement('img');
img.style.visibility = 'hidden';
img.style.position = 'fixed';
img.src = url;
img.onerror = continueBtn; // What to do on error function
document.body.appendChild(img);
}
Another way to do this is is with PHP.
You could add
<?php
if (file_exists('/index.php'))
{
$url = '/index.php';
} else {
$url = '/notindex.php';
}
?>
And then
<a href="<?php echo $url; ?>Link</a>

Categories

Resources