i have one nested casper.repeat in casper.repeat loop. and i need escape from inner and continue from first casper.start().repeat(500... when one element appears.. i scrape site where i pass pages and in one of this pages(i dont know exactly which one) one element can appear and i need to to break this loop and continue from start point.
well this is my code:
casper.start().repeat(500, function() {
if(counter==11) {
page_counter++;
counter=0;
}
casper.open('http://my.ya.ru/clubs_rating.xml?p=' + page_counter);
var links = this.getElementsInfo('dl.info dt a');
this.echo('Opened page: ' + this.getCurrentUrl());
casper.repeat(40, function() {
//here i need make **waitFor** to check element every time////////
//and if it's here - break loop and go to start point/////////////
if(innercounter==19) {
ipagecounter=ipagecounter+20;
innercounter=0;
}
Try:
casper.waitForSelector('#your_selector_id', function() {
test.assertExists('#your_selector_id', "We've find this element\^_^/!");
}, function () {
this.echo('Wasn't found in 10 seconds!');
}, 10000);
Or look at https://github.com/yotsumoto/casperjs-goto
Goto is a peace of sadness, but I believe might be useful.
casper.start();
casper.repeat(500, function() {
casper.open('http://my.ya.ru/clubs_rating.xml?p=' + page_counter);
casper.label( "LABER_FOR_BREAK" );
var counter=0;
casper.label( "LOOP_START" );
casper.then(function(){
//check selector
if( /*true selector assertion*/ ){
this.goto( "LABEL_FOR_BREAK" );
};
});
casper.then(function() {
counter++;
this.echo( counter );
});
casper.then(function() {
if( counter<41 ){ this.goto( "LOOP_START" ); }
});
});
casper.run( function() {
this.dumpSteps( true );
this.exit();
});
Does this make sense?
Related
I'm trying to load three different html files into a div, one after the other, with a delay of 5 seconds. After it cycles through all three I want it to carry on repeating. I tried using timeout to do this but its still not working.Any help would be appreciated.. code snippet below
<script type="text/javascript">
$(document).ready(function() {
jQuery(window).load (function timeout() {
setTimeout(function () {
if($("#news_sections").hasClass("news1")){
$("#news_sections").attr('class', "news2");
$( "#news_sections" ).load( "section2.html" );
}else if($("#news_sections").hasClass("news2")){
$("#news_sections").attr('class', 'news3');
$( "#news_sections" ).load( "section3.html" );
}else{
$("#news_sections").attr('class', 'news1');
$( "#news_sections" ).load( "section1.html" );
};
timeout();
}, 4000);
});
});
});
</script>
Untested but you should do something like this:
$(function(){
var curIdx = 0, /* internal counter */
urls = ['page1.html','page2.html','page3.html'], /* your urls*/
doCache = true, /* set to false to disable caching */
cache = {} /* storage */;
function nextPage(){
var data = false,
url = urls[curIdx];
if(doCache && cache[url]) {
data = cache[url];
}
curIdx += 1;
// all urls displayed - reset counter, show first page again
if(curIdx == urls.length) {
curIdx = 0;
}
// load data (and cache it, if doCached option is true)
if(!data){
$("#content").load(url, function(data){
cache[url] = data;
nextTimer();
})
} else {
$("#content").html(data);
nextTimer();
}
};
// now to timeout
function nextTimer(){
window.setTimeout(function(){ nextPage() }, 5000); // 5 Seconds
}
// and run it...
nextPage();
});
Be aware that this might not work with external urls.
You can use this, instead of changing classes and depending on them.
In case you have more than 10 sectionX.html files, you will need to write a lot of code there. So if you make an counter, you have to change only the if statement to (count > X) where X = number of templates you have.
var count = 1;
setInterval(function () {
// If the count is more 3, we reset the count to 1.
if (count > 3) {
count = 1;
}
// If you are using "newsX" class for looping propose only,
// You can remove .attr() method in my solution.
$("#news_sections").attr('class', "news" + count);
// clear news section
$("#news_sections").empty();
// Load the count number sectionX.html file
// Also increase count number with 1 (count++)
$("#news_sections").load( "section" + count++ + ".html" );
}, 1500);
Your code seems a bit convoluted, and you should probably not use setTimeout like that. I believe what you're looking for is setInterval, which executes the same function repeatedly, every X milliseconds.
I simplified it a bit. First, declare the loopNews() function, and then set the timeout call when the document is ready.
function loopNews(){
if($("#news_sections").hasClass("news1")){
$("#news_sections").attr('class', "news2");
$("#news_sections").load( "section2.html" );
}else if($("#news_sections").hasClass("news2")){
$("#news_sections").attr('class', 'news3');
$("#news_sections").load( "section3.html" );
}else{
$("#news_sections").attr('class', 'news1');
$("#news_sections").load( "section1.html" );
}
}
$(document).ready(function() {
window.setInterval(loopNews, 5000);
});
I currently have two CasperJS scripts that I want to combine into one for usability purposes. test1.js scrapes a webpage for links ( <a> elements). All the resulting links scraped are stored in an array urls. Script test2.js takes a link and extracts youtube src link if present from iframe.
How can I gather all links (test1.js) and then visit each link to extract a youtube link (test2.js), finally store YouTube links in array and display result?
test1.js
var urls = [];
var casper = require('casper').create();
function getNumberOfItems(casper) {
return casper.getElementsInfo(".listview .badge-grid-item").length;
}
function tryAndScroll(casper) {
casper.page.scrollPosition = { top: casper.page.scrollPosition["top"] + 4000, left: 0 };
var info = casper.getElementInfo('.badge-post-grid-load-more');
if (info.visible) {
var curItems = getNumberOfItems(casper);
if( curItems <= 60 ) {
casper.waitFor(function check(){
return curItems != getNumberOfItems(casper);
}, function then(){
tryAndScroll(this);
}, function onTimeout(){
this.echo("Timout reached");
}, 20000);
}
} else {
casper.echo("no more items");
}
}
casper.start('http://example.com', function() {
tryAndScroll(this);
});
casper.then(function() {
casper.each(this.getElementsInfo('.title'), function(casper, element, j) {
var url = element["attributes"]["href"];
urls.push(url);
});
});
casper.run(function() {
this.echo(urls.join('\n')).exit();
this.echo(urls.length + ' links found');
});
test2.js (Currently only takes one url)
var casper = require('casper').create();
var yt_links = [];
casper.start('http://example.com', function() {
this.click('.responsivewrapper');
});
casper.then(function() {
casper.each(this.getElementsInfo('.badge-youtube-player'), function(casper, element, j) {
var url = element["attributes"]["src"];
yt_links.push(url);
});
});
casper.run(function() {
this.echo(yt_links.join('\n')).exit();
this.echo(yt_links.length + ' link(s) found');
});
start and run functions of CasperJS can only be used once, but there is also the thenOpen function to open a URL in a step. All then* and wait* functions are step functions. By calling them, you essentially schedule the steps that those functions represent. Furthermore, you can nest CasperJS steps. So that the steps further down in the script, but higher up in the tree will only be executed when all the nested steps are finished.
// last step of test1.js
casper.then(function() {
this.getElementsInfo('.title').forEach(function(element) {
// skip elements that don't have a href attribute...
if (!element.attributes.href) {
return;
}
// here come the contents of test2.js
casper.thenOpen(element.attributes.href, function() {
this.click('.responsivewrapper');
}).then(function(){
...
}).then(function(){
this.echo(yt_links.join('\n')).exit();
this.echo(yt_links.length + ' link(s) found');
});
});
});
I used the builder/promise pattern to make the code example a little shorter.
I found good answers here to how pause and resume a setTimeout. Very useful.
But how can I resolve a similar issue but with an array of setTimeouts?
I need a click on any element to pause and then resume after the click on the setTimeout in the array where it was stopped last time and so on.
My code so far works except the fact that it resumes the timeout sets at the beginning. Is there a way to check on which setTimeout element the pause was made and resume at this point again? I presume the second definition of var fadeTrailer has to subtract those elements that have been activated already. Somehow it should work with the index. But I don’t know how. Thanks for help!
//automatic fader
fadeTrailer = [
setTimeout( function() {
//first action
}, 9500),
setTimeout( function() {
//second action )
}, 19000),
setTimeout( function() {
//third action
}, 32000),
];
$("#Trailer").on( 'click.resumeTrailerFade', function() { resumeTrailerFade(); } );
function resume
function resumeTrailerFade() {
$.each( fadeTrailer, function(i, timer) {
clearTimeout(timer);
} );
fadeTrailer = [
setTimeout( function() {
//first action
}, 9500),
setTimeout( function() {
//second action )
}, 19000),
setTimeout( function() {
//third action )
}, 32000),
];
};
I hope this is the right way to do this here. Good but also difficult forum for beginners ;-)
What I did now is that I declared a timeline variable at the start as:
var fadingTimeline = [
setTimeout( function() {
//anything
fadeState = 0;
}, 9500),
setTimeout( function() {
//anything
fadeState = 1;
}, 19000),
setTimeout( function() {
//anything
fadeState = 2;
}, 32000),
];
Then I put in the first appearance:
//automatic fader
fadeTrailer = fadingTimeline;
// interrupts automatic fader and restarts it (to give user time to stay on each work when clicking elements in it)
$("#Trailer").on( 'click.resumeTrailerFade', function() { resumeTrailerFade(); } );
Then for the resumeTrailerFade() I tried to grep the array of the elements by index using the fadeState variable like:
function resumeTrailerFade() {
$.each( fadeTrailer, function(i, timer) {
clearTimeout(timer);
} );
//filter timeline array for already passed setTimeouts
fadeTrailerRemain = $.grep( fadingTimeline, function(n) {
return ( n.index < fadeState );
});
}
I know the last part is silly code, just for explaining my idea.
Is there someone out there able to follow my idea and put it into real working code? Would be so awesome!
Edited: Somehow I missed Igoel's comment where he says the same thing. Sorry about that.
There is no simple way to query a timeout to see how much time has elapsed. You can store the start time of a timeout in a separate variable and then calculate the difference explicitly.
FWIW, note that JavaScript timeouts are not necessarily accurate as JavaScript is a single-threaded execution environment.
the code you showed me, is in fact awesome for me!
I changed it a little (as I don’t need buttons etc.)
So I declared the variables this way:
var first = function() {
// do the first thing
}
var second = function() {
// do the second thing
}
var third = function() {
// do the third thing
}
var fourth = function() {
// do the fourth thing
}
var fifth = function() {
// do the fifth thing
}
//…
var timer;
var timeFrames = {
95: [first],
190: [second],
320: [third],
420: [fourth],
510: [fifth],
//…
};
var timerPaused = false;
var maxStep = 510;
var stepSize = 100;
var currentStep = 0;
var intervalTimer = function() {
if ( !timerPaused ) { currentStep ++; }
if ( !!timeFrames[currentStep] ) {
if ( !!timeFrames[currentStep][0] ) {
( timeFrames[currentStep][0])(timeFrames[currentStep][1] );
}
}
if ( currentStep >= maxStep ) {
timer = window.clearInterval(timer);
currentStep = 0;
}
}
On the right place inside a function where I needed it so start automatically I put:
//automatic trailer fader
timer = window.setInterval( intervalTimer, stepSize );
// interrupts automatic fader
// restarts it (to give user time to stay on clicked elements within the fading content)
$("#Trailer").on( 'click.resumeTrailerFade', function() {
timerPaused = true;
setTimeout( function() { timerPaused = false; }, 15000 ); // give some extra time when anything clicked before resume automatic fade again
} );
Then finally to abolish all I put:
//stops automatic trailer fader definitely without resume
timerPaused = true;
window.clearInterval(timer);
$("#Trailer").off( 'click.resumeTrailerFade' );
Works perfect even I am a aware that for you profs there might be still some strange things in it.
So feel free to comment about it. Every help to improve is welcome!
Thank you so far for great help, without it I would never have made it.
This is the html. If a link is clicked I want to replace the span-element in front of it with some text.
<p><span id="sp1">that1</span> Update1</p>
<p><span id="sp2">that2</span> Update2</p>
<p><span id="sp3">that3</span> Update3</p>
<p><span id="sp4">that4</span> Update4</p>
<p><span id="sp5">that5</span> Update5</p>
As you can see, my idea was to give the spans en the anchors identical id's and a number.
In my jquery-code I loop through all the anchor-elements, give them a click-event that causes the span-element in front of it to be replaced.
<script type="text/javascript" >
$(document).ready(function() {
var numSpans = $("span").length;
for (n=0;n<=numSpans;n++) {
$("a#update" + n).click(function(e){
$('span#sp' + n).replaceWith('this');
e.preventDefault();
});
}
});
</script>
For some reason this does not work.
What am I doing wrong?
The problem with your original code is that you're creating a closure on the variable n. When the event handler is called, it is called with the value of n at the point of invocation, not the point of declaration. You can see this by adding an alert call:
$(document).ready(function() {
var numSpans = $("span").length;
for (n = 1; n <= numSpans; n++) {
$("a#update" + n).click(function(e) {
alert(n); //Alerts '6'
$('span#sp' + n).replaceWith('this');
e.preventDefault();
});
}
})
One way to fix this is to create a closure on the value of n in each iteration, like so:
$(document).ready(function() {
var numSpans = $("span").length;
for (n = 1; n <= numSpans; n++) {
$("a#update" + n).click(
(function(k) {
return function(e) {
alert(k);
$('span#sp' + k).replaceWith('this');
e.preventDefault();
}
})(n)
);
}
})
However, this is messy, and you'd do better to use a more jQuery-y method.
One way to do this would be to remove the ids from your code. Unless you need them for something else, they're not required:
<p><span>that1</span> Update1</p>
<p><span>that2</span> Update2</p>
<p><span>that3</span> Update3</p>
<p><span>that4</span> Update4</p>
<p><span>that5</span> Update5</p>
jQuery:
$(function() {
$('a.update').live('click', function() {
$(this).siblings('span').replaceWith("Updated that!");
});
});
jsFiddle
Don't create functions in a loop. With jQuery, there's no need for an explicit loop at all.
$(function()
{
$('span[id^=sp]').each(function(n)
{
$('#update' + n).click(function(e)
{
$('#sp' + n).replaceWith(this);
return false;
});
});
});
Demo: http://jsfiddle.net/mattball/4TVMa/
You can do way better than that, though:
$(function()
{
$('p > a[id^=update]').live('click', function(e)
{
$(this).prev().replaceWith(this);
return false;
});
});
Demo: http://jsfiddle.net/mattball/xySGW/
Try this:
$(function(){
$("a[id^='update']").click(function(){
var index = this.id.replace(/[^0-9]/g, "");
$("span#sp" + index).replaceWith(this);
e.preventDefault();
});
});
what I got now is:
function()
{
setInterval("getSearch()",10000);
getSearch();
}
);
But I want this interval to pause if the mouse cursor is placed inside a div on my website. How do I attack this problem? Surely I need to give the div an ID.. But some input on how to make the javascript/jquery part is much appreciated.
EDIT: More of my code.. I'm not quite sure where to insert the code in the answers inside this:
$(
function()
{
setInterval("getSearch()",10000);
getSearch();
}
);
TwitterCache = {};
function getSearch()
{
var url = "http://search.twitter.com/search.json?q=test&refresh=6000&callback=?"; // Change your query here
$.getJSON
(
url,
function(data)
{
if( data.results ) // Checks to see if you have any new tweets
{
var i = -1, result, HTML='', HTML2='';
while( (result = data.results[++i]) && !TwitterCache[result.id] )
{
insert html.. blabla}
setInterval returns a "reference" to that interval you set up, allowing you to stop it with window.clearInterval(), and that's what you have to do:
var myInterval;
function startMyInterval() {
if (!myInterval) {
// It's better to call setInterval width a function reference, than a string,
// also always use "window", in case you are not in its scope.
myInterval = window.setInterval(getSearch, 10000);
}
}
function stopMyInterval() {
if (myInterval) {
window.clearInterval(myInterval);
}
}
startMyInterval(); // Start the interval
jQuery("#myDiv").hover(stopMyInterval, startMyInterval);
Set a global variable
var intID;
Assign setInterval to this variable
intID = setInterval("getSearch()",10000);
Set an id for the div
$("#divid").hover(function(){
clearInterval(intID);
},
function(){
// set the interval again
});
I think this should work:
$("#divID").hover(
function () {
PauseTheInterValThing()
},
function()
{
setInterval("getSearch()",10000);
getSearch();
}
);
The simplest way, and the shortest
Simplest method would be:
<div id="yourDiv">
EXAMPLE TEXT
</div>
<script language="Javascript">
var interval = setInterval("getSearch()",1000);
document.getElementById("yourDiv").addEventListener('mouseover', function()
{
clearInterval(interval);
},false);
document.getElementById("yourDiv").addEventListener('mouseout', function()
{
interval = setInterval("getSearch()",1000);
},false);
</script>
insert this in your dom-ready function:
var inv = setInterval("getSearch",1000);
$('#yourdiv').mouseover(function(){
clearInterval(inv);
}).mouseout(function(){
inv = setInterval("getSearch",1000);
})