I'd like to show series of dynamically loaded images named in a structured way in my website. Images are located in a different domain which causes Same Origin Policy restriction. I cannot use $.ajax.
I build my url like with a counter such as www.example.com/Images/img-1.jpg, www.example.com/Images/img-2.jpg and it goes...
I've tried several other answers from similar posts but couldn't make them work. Either the loop runs forever or it never finds the images even though they exist in the path.
1st try:
ShowImages: function () {
var urlBase = 'http://www.example.com/Images/img-';
var i = 1;
while (true) {
var url = urlBase + i + '.jpg';
var imgDom = new Image();
imgDom.onload = function () {
alert('worked');
i++;
};
imgDom.onerror = function () {
return; // I want to either break the while loop, or return from ShowImages function
};
imgDom.src = url;
}
},
It never hits the .onerror.
2nd try:
ShowImages: function () {
var urlBase = 'http://www.example.com/Images/img-';
var i = 1;
while (true) {
var url = urlBase + i + '.jpg';
var imgDom = document.createElement("img");
$(imgDom).attr('src', url);
if (imgDom.complete) {
alert('worked');
i++;
} else {
break;
}
}
},
It never hits the .complete.
Trying with your first option (you basically need to chain them)
ShowImages(1);
ShowImages: function (counter) {
var urlBase = 'http://www.example.com/Images/img-';
var url = urlBase + counter + '.jpg';
var imgDom = new Image();
imgDom.onload = function () {
alert('worked');
ShowImages(counter+1);
};
imgDom.onerror = function () {
alert("all images done..");
return; // I want to either break the while loop, or return from ShowImages function
};
imgDom.src = url;
};
Related
The following code is a simple scraper written in CasperJS.
var casper = require('casper').create();
var url = casper.cli.get(0);
var page1 = casper.cli.get(1);
var page2 = casper.cli.get(2);
//console.log(page2);
var proxy = casper.cli.get(3);
//alert(page1);
var exp = /[-a-zA-Z0-9#:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9#:%_\+.~#?&//=]*)?/gi;
var regex = new RegExp(exp);
var baseUrl = url;
//console.log(baseUrl);
var nextBtn = "a.navigation-button.next";
var allLinks = [];
casper.start(baseUrl);
casper.waitForSelector(nextBtn, processPage);
casper.run();
function processPage() {
for (var i = page1; i < page2; i = i + 1) {
console.log(i);
var pageData = this.evaluate(getPageData);
allLinks = allLinks.concat(pageData);
if (!this.exists(nextBtn)) {
return;
};
this.thenClick(nextBtn).then(function() {
//this.echo(i);
this.echo(this.getCurrentUrl());
//this.wait(1000);
});
};
}
function getPageData(){
//return document.title;
var links = document.getElementsByClassName('pro-title');
links = Array.prototype.map.call(links,function(link){
return link.getAttribute('href');
});
return links;
};
casper.then(function(){
//require('utils').dump(allLinks);
this.each(allLinks,function(self,link){
if (link.match(regex)) {
self.thenOpen(link,function(a){
jsonObj = {};
jsonObj.title = this.fetchText('a.profile-full-name');
jsonObj.services = this.getHTML('div.info-list-text span:nth-child(2) span');
jsonObj.services = jsonObj.services.replace(/&/g,"and");
jsonObj.location = this.getHTML('div.pro-info-horizontal-list div.info-list-label:nth-child(3) div.info-list-text span');
//jsonObj.contact = this.fetchText('span.pro-contact-text');
jsonObj.description = this.getHTML('div.profile-about div:nth-child(1)');
//jsonObj.description.replace(/\s/g, '');
//require('utils').dump(jsonObj);
//jsonObj.description = jsonObj.description.replace(/[\t\n]/g,"");
//jsonObj = JSON.stringify(jsonObj, null, '\t');
//console.log(i);
require('utils').dump(jsonObj);
});
};
});
});
I am executing this script as follows,
casperjs scraping.js http://www.houzz.com/professionals/c/Chicago--IL/p/15 1 3
The first CLI argument is the starting URL. The second and third arguments are the starting and ending page numbers of the scrape.
I am able to extract data from the first page, but I don't understand why I am not able to extract data from any of the consequent pages.
You cannot mix synchronous and asynchronous code like this in processPage. The loop is immediately executed, but the click and the loading of the next page happens asynchronously. The evaluation of the page has to be done asynchronously:
function processPage() {
for (var i = page1; i < page2; i = i + 1) {
this.then(function(){
console.log(i);
var pageData = this.evaluate(getPageData);
allLinks = allLinks.concat(pageData);
if (!this.exists(nextBtn)) {
return;
}
this.thenClick(nextBtn).then(function() {
this.echo(this.getCurrentUrl());
});
});
};
}
I have implemented the code to check if the number of image files present in the server and then use it for gallery. The number of images are found correct but only the first image loads and does not change .
var gallerylength;
var galleryid = 1;
function UrlExists(url)
{
var http = new XMLHttpRequest();
http.open('HEAD', url, false);
http.send();
return http.status!=404;
}
function checksrc()
{
var index = 1;
var src = "images/splash/gallery/img";
for(index=1;UrlExists(src+index+".jpg");index++);
gallerylength = index;
}
function setimg()
{
var src = "images/splash/gallery/img";
{
$("#gallerywindow").attr("src",src+galleryid+".jpg");
if(galleryid<gallerylength-1)
galleryid++;
else
galleryid = 1;
}
}
$(document).ready(function(event)
{
checksrc();
setInterval(setimg(),1000);
});
In line: setInterval(setimg(),1000); you are calling the function, must be a reference to it: setInterval(setimg,1000);
$(document).ready(function(event)
{
checksrc();
setInterval(setimg, 1000);
//or
setInterval(function(){
setimg();
}, 1000);
});
This app https://developer.mozilla.org/en-US/demos/detail/meet-me-there/launch accepts uploaded photos, attaches a qr code to them, and then allows you to share them. I've attached below the JavaScript for everything except the QR functionality. The app doesn't use jQuery, but at the beginning it assigns a function to the $.
window.onload = function(){
var $ = function(id){
console.log(id);
return document.getElementById(id);
},
When I run the app with the console.log in the above position, it shows that quite a few 'ids' are getting passed through that console.log(id). As the file loads, it logs 'surface', 'cam' and 'upload' and, as you engage the app, it logs 'result', 'sharer', 'uploadedURL' and many others. Problem is that I don't see how everything keeps getting passed through that function for the console.log to log the different 'id's at that point in the code. Therefore, I wonder what the significance of '$' is in this context (no jQuery). Specifically, by creating that '$' function, is it called anytime that any of the other events with $ are run, such as $('upload').onclick = function(){...
Is it working similar to how adding a prototype is working in jquery by using $.prototype.function() in jquery. If so, where does it get this functionality from if there's no jQuery.
window.onload = function(){
var $ = function(id){
console.log(id);
return document.getElementById(id);
},
canvas = $('surface'),
ctx = canvas.getContext('2d'),
watcher, loc='No location provided', located;
$('cam').onchange = function(event){
console.log(event);
console.trace();
var files = event.target.files,
file;
if (files && files.length > 0) {
file = files[0];
try {
var URL = window.URL || window.webkitURL || window.mozURL;
var imgURL = URL.createObjectURL(file);
var img = new Image();
img.id = "tester";
//Load it onto the canvas
img.onload = function() {
console.trace();
canvas.width = this.width;
canvas.height = this.height;
$('info').innerHTML = ("Width: " + this.width + "px, Height: " + this.height + "px");
$('result').width = 400;
$('result').height = (400 / (this.width/this.height)) >> 0;
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
var codeSize = (canvas.height/4) >> 0;
var imgn = new Image();
imgn.onload = function(){
ctx.drawImage(imgn, (canvas.width-5- codeSize), (canvas.height-5-codeSize), codeSize, codeSize);
$('result').src = canvas.toDataURL();
}
imgn.src = (QR.encode(loc, codeSize, 5));
}
img.src = imgURL;
} catch (e) {
console.log("error: " + e);
}
}
},
// borrowed this functionality from cgack's demo
// https://developer.mozilla.org/en-US/demos/detail/snap-and-share
$('upload').onclick = function(){
$('infomsg').style.display = 'block';
var url = "http://api.imgur.com/2/upload.json",
params = new FormData(),
http = new XMLHttpRequest();
params.append('key','29a8b1db1d8fda0df87006def2307242');
params.append('image',canvas.toDataURL().split(',')[1]);
http.open("POST", url);
http.onload = function() {
var url = JSON.parse(http.responseText).upload.links.imgur_page;
$('uploadedUrl').href = url;
$('uploadedUrl').innerHTML = url;
$('shareFb').href = ("http://www.facebook.com/sharer.php?u="+url);
$('shareTwitter').href = ("http://twitter.com/intent/tweet?url="+url);
$('sharer').style.display = 'block';
$('infomsg').style.display = 'none';
};
http.send(params);
console.log(params);
};
watcher = navigator.geolocation.watchPosition(function(position){
console.trace();
console.log("navigator");
loc = "geo:" + position.coords.latitude + "," +position.coords.longitude;
located = true;
}, function(error){
if(error.code == error.PERMISSION_DENIED || error.code == error.POSITION_UNAVAILABLE)
alert('damn, we were not able to locate you. sorry.');
}
);
};
$ is just a variable name, like any other. It has no special meaning.
"Problem is that I don't see how everything keeps getting passed through that function for the console.log to log the 'id' at that point in the code."
Any time you see $, it's a reference to the function. So a () after it invokes it with the given argument. It's just like any other function, just with a funny name referencing it.
"Therefore, I wonder what the significance of '$' is in this context (no jQuery). Specifically, by creating that '$' function, is it called anytime that any of the other events with $ are run"
Again, no real significance. It's just a function name. If you renamed all the instances of $ to byId, it would behave the same.
window.onload = function(){
// var $ = function(id){
var byId = function(id){
console.log(id);
return document.getElementById(id);
},
canvas = foo('surface'),
ctx = canvas.getContext('2d'),
watcher, loc='No location provided', located;
byId('cam').onchange = function(event){
/* a bunch of code */
},
byId('upload').onclick = function(){
/* a bunch of code */
};
// rest of the code
};
What's wrong with this code:
var images = [];
function getImages() {
var st = true;
var i = 1;
var url;
var ob;
while(st) {
if(i < 10) {
url = "http://rachel-b.org/gallery/albums/Events/2012/May%2008%20-%20Rachel%20Bilson%20Celebrates%20Edie%20Rose%20Home%20Collection/thumb_00" + i + ".jpg";
ob = new Image();
ob.src = url;
st = checkIfImageExists(ob);
images.push(ob);
}
if(i >= 10 && i < 100) {
url = "http://rachel-b.org/gallery/albums/Events/2012/May%2008%20-%20Rachel%20Bilson%20Celebrates%20Edie%20Rose%20Home%20Collection/thumb_0" + i + ".jpg";
ob = new Image();
ob.src = url;
st = checkIfImageExists(ob);
images.push(ob);
}
if(i >= 100) {
url = "http://rachel-b.org/gallery/albums/Events/2012/May%2008%20-%20Rachel%20Bilson%20Celebrates%20Edie%20Rose%20Home%20Collection/thumb_" + i + ".jpg";
ob = new Image();
ob.src = url;
st = checkIfImageExists(ob);
images.push(ob);
}
i++;
}
}
function checkIfImageExists(o) {
var e = document.createElement("img");
e.style.display = "none";
document.getElementsByTagName("body")[0].appendChild(e);
e.src = o.src;
var res = e.width;
document.getElementsByTagName("body")[0].removeChild(e);
console.log(res);
if(res === 0) {
return false;
} else {
return true;
}
}
getImages();
function outPut() {
for(var i = 0; i < images.length; i++) {
console.log(images[i]);
}
}
outPut();
​DEMO
Why doesn't it output all array elements at once?
At the same time, every time I press run button, it outputs n+1 array elements. How come?
Here is my rewrite
DEMO stops when there are no more images found - in this case at 106 images
var images =[];
var baseUrl = "http://rachel-b.org/gallery/albums/Events/2012/May%2008%20-%20Rachel%20Bilson%20Celebrates%20Edie%20Rose%20Home%20Collection/thumb_";
function pad(num) {
var str = "00"+num;
return str.substring(str.length-3);
}
function output() {
for (var i=0;i<images.length;i++) {
console.log(images[i].src)
}
}
function getImages(){
var ob = new Image();
var url = baseUrl+pad(images.length+1)+".jpg"
ob.onload=function() {
images.push(ob);
getImages();
}
ob.onerror=function() {
output();
}
ob.src= url;
}
getImages();
Your checkIfImageExists() function is the cause. I understand what you are trying to accomplish but you are checking for a width without giving the image time to load. You should bind to onload and onerror for the image object. (See http://lucassmith.name/2008/11/is-my-image-loaded.html for more details).
If you really want these images to load asynchronously, this while loop is very dangerous, you'd be better off with already knowing the top limit rather than trying to guess. If you do want async and have an unknown max...then you should chunk into a limited amount of images at once to load (as well as add some type of setInterval. Otherwise, with this setup, by the time your server returns a 404 for an image, your script would have already tried to load several thousand more invalid images.
If you need a code example let me know but this should at least point you in the right direction.
As seen below I'm trying to get #currentpage to pass client params
Can someone help out thanks.
$(document).ready(function() {
window.addEventListener("load", windowLoaded, false);
function windowLoaded() {
chrome.tabs.getSelected(null, function(tab) {
document.getElementById('currentpage').innerHTML = tab.url;
});
}
var url = $("currentpage");
// yes I relize this is the part not working.
var client = jQuery.param("currentpage");
var page = jQuery.param("currentpage");
var devurl = "http://#/?clientsNumber=" + client + "&pageName=" + page ;
});
This is a method to extract the params from a url
function getUrlParams(url) {
var paramMap = {};
var questionMark = url.indexOf('?');
if (questionMark == -1) {
return paramMap;
}
var parts = url.substring(questionMark + 1).split("&");
for (var i = 0; i < parts.length; i ++) {
var component = parts[i].split("=");
paramMap [decodeURIComponent(component[0])] = decodeURIComponent(component[1]);
}
return paramMap;
}
Here's how to use it in your code
var url = "?c=231171&p=home";
var params = getUrlParams(url);
var devurl = "http://site.com/?c=" + encodeURIComponent(params.c) + "&p=" + encodeURIComponent(params.p) + "&genphase2=true";
// devurl == "http://site.com/?c=231171&p=home&genphase2=true"
See it in action http://jsfiddle.net/mendesjuan/TCpsD/
Here's the code you posted with minimal changes to get it working, it also uses $.param as it's intended, that is to create a query string from a JS object, this works well since my suggested function returns an object from the url
$(document).ready(function() {
// This does not handle arrays because it's not part of the official specs
// PHP and some other server side languages support it but there's no official
// consensus
function getUrlParams(url) {
var paramMap = {};
var questionMark = url.indexOf('?');
if (questionMark == -1) {
return paramMap;
}
var parts = url.substring(questionMark + 1).split("&");
for (var i = 0; i < parts.length; i ++) {
var component = parts[i].split("=");
paramMap [decodeURIComponent(component[0])] = decodeURIComponent(component[1]);
}
return paramMap;
}
// no need for the extra load listener here, jquery.ready already puts
// your code in the onload
chrome.tabs.getSelected(null, function(tab) {
document.getElementById('currentpage').innerHTML = tab.url;
});
var url = $("currentpage");
var paramMap = getUrlParams(url);
// Add the genphase parameter to the param map
paramMap.genphase2 = true;
// Use jQuery.param to create the url to click on
var devurl = "http://site.com/?"+ jQuery.param(paramMap);
$('#mydev').click( function(){
window.open(devurl);
});
});