JQuery pause slideshow and resume with setInterval - javascript

I'm aware there's plenty of JQuery slideshows out there but I'm coding my own and have come across an obstacle I've not found an answer to specifically.
Background: An automated JQuery Slideshow plugin with pause/resume on hover/out
Problem: How to pause the slideshow on mousenter, and then finish the remaining time period of the setInterval on mouseleave instead of firing the setInterval again.
Solution: I think the only way to do this would be to use a self-invoking method with a delay attached and a stop() to handle the mouse behaviour which would allow the paused animation to resume for its proper remainder rather than firing the method again?
What are your thoughts?
Here's the code:
(function( $ ){
var methods = {
init: function() {
var cycle = window.setInterval(methods.automate, 1000);
$('.slider_control').on('click', 'span', function(){
methods.automate( $(this).attr('slideNumber') );
});
$('.slider_master_container')
.on({
'mouseenter': function() {
clearInterval(cycle);
},
'mouseleave': function() {
cycle = window.setInterval(methods.automate, 1000);
}
});
},
automate: function( el ) {
var $active = $('.slide.active'),
$next = el ? $('.slide[slideNumber=' + el) : $active.nextOrFirst();
$next.css('z-index', 2);
$active.fadeOut(1500, function() {
$active.css('z-index', 1).show().removeClass('active');
$next.css('z-index', 3).addClass('active');
});
}
};
$.fn.smartSlider = function( method ) {
if ( methods[method] ) {
return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof method === 'object' || ! method ) {
return methods.init.apply( this, arguments );
} else {
$.error( 'Method ' + method + ' does not exist on jQuery.smartSlider' );
}
};
})( jQuery );

Related

Prototype.js how to fix use of clearTimeout( )

I'm using Prototype.js to load an html element when the user performs a mouseover on certain list items. I'm using setTimeout() to load the content only if the mouse is still over the list item after a given amount of time. I want to use clearTimeout when the user performs a mouseout on the same list item.
clearTimeout() is not clearing my timeout. I am pretty sure this is because of a common variable scope issue hidden from me by my lack of familiarity with Prototype.js
Can someone point out the flaw in this code or determine what I need to add to make the clearTimeout() function work properly?
document.observe( 'dom:loaded', function() {
var timeout;
$$('.nav-primary li.category').each( function( item ) {
item.observe('mouseover', function(event) {
event.stopPropagation();
categoryId = event.currentTarget.id;
getCategoryBlurb(categoryId);
timeout = setTimeout( function() {
showCategoryInfo(categoryData, categoryId);
}, waitTime);
});
item.observe('mouseout', function(event) {
event.stopPropagation();
clearTimeout(timeout);
});
});
});
Updated Code
$$('.nav-primary li.category').each( function( item ) {
var timeout = null;
item.observe('mouseover', function(event) {
event.stopPropagation();
categoryId = event.currentTarget.id;
getCategoryBlurb(categoryId);
if( timeout === null ) {
timeout = setTimeout( function() {
showCategoryInfo(categoryData, categoryId);
}, waitTime);
}
console.log(timeout);
});
item.observe('mouseout', function(event) {
if( timeout !== null ) {
console.log(timeout);
clearTimeout(timeout);
timeout = null;
}
});
});
clear the timeout before you set it
if (timeout) { clearTimeout(timeout); }
timeout = setTimeout( function() { /* code here */ });

JQuery Marquee sliding top

Hye,
Just a newbie trying to get something done and out of idea's I have a ul that is marqued from jquery function its marqueed left that means its sliding left what I want to do is to make it slide top
i Have made a working fiddle here
http://jsfiddle.net/arafays/wnXh8/
(function($)
{
var methods =
{
init : function( options )
{
return this.each(function()
{
var _this=$(this);
_this.data('marquee',options);
var _li=$('>li',_this);
_this.wrap('<div class="slide_container"></div>')
.height(_this.height())
.hover(function(){if($(this).data('marquee').stop){$(this).stop(true,false);}},
function(){if($(this).data('marquee').stop){$(this).marquee('slide');}})
.parent()
.css({position:'relative',overflow:'hidden','height':$('>li',_this).height()})
.find('>ul')
.css({width:screen.width*2,position:'relative'});
for(var i=0;i<Math.ceil((screen.width*3)/_this.width());++i)
{
_this.append(_li.clone());
}
_this.marquee('slide');});
},
slide:function()
{
var $this=this;
$this.animate({'left':$('>li',$this).width()*-1},
$this.data('marquee').duration,
'swing',
function()
{
$this.css('left',0).append($('>li:first',$this));
$this.delay($this.data('marquee').delay).marquee('slide');
}
);
}
};
$.fn.marquee = function(m)
{
var settings={
'delay':4000,
'duration':2000,
'stop':true
};
if(typeof m === 'object' || ! m)
{
if(m){
$.extend( settings, m );
}
return methods.init.apply( this, [settings] );
}
else
{
return methods[m].apply( this);
}
};
}
)( jQuery );
jQuery(document).ready(
function(){jQuery('.some ul').marquee({delay:3000});}
);
I just want to make it slide up instead of sliding left I tried making append top and doing some other some stuff but its making full ul slide up leaving blank space
Like this?
http://jsfiddle.net/wnXh8/5/
$this.animate({'top':$('>li',$this).height()*-1},
$this.data('marquee').duration,
'swing',
function()
{
$this.css('top',0).append($('>li:first',$this));
$this.delay($this.data('marquee').delay).marquee('slide');
}
);

Keep calling on a function while mouseover

how do I keep calling a function on mouseover while the mouse is hovered over an html element
Example:
<script>
function a() {
"special code hear"
}
</script>
<div onmouseover( 'a()')> </div>
How can I keep calling the function a while the mouse is hovered over the div instead of having it call the function once.
Events don't repeat automatically. You can use a timer to repeat the command while the mouse is over, but don't forget to stop the timer at the onmouseout event. You'll need a variable outside of the functions to track the timer so it can be cancelled, which is why we have var repeater declared separately.
<script>
var repeater;
function a() ...
</script>
<div onmouseover="repeater=setInterval(a(), 100);" onmouseout="clearInterval(repeater);"></div>
Here is one possible solution using setTimeout (DEMO HERE), it will be repeated every second:
HTML CODE:
<div id='div'>test</div>
JS code :
<script>
document.getElementById('div').onmouseover=function(){a();};
function a(){
//some code here
setTimeout(a,1000);
}
</script>
TRY THIS FIDDLE
http://jsfiddle.net/C4AVg/
var pee = '';
$('#poop').mouseover(function(){
pee = setInterval(function() {
      // Do something every 5 seconds
alert('hi');
}, 1000);
});
$('#poop').mouseout(function() {
clearInterval(pee);
});
As others already mentioned calling a function repeatedly can be achieved using setInterval and stopping it can be done using clearInterval.
In case you're looking for a general solution you could use something like this:
function repeatWhileMouseOver(element, action, milliseconds) {
var interval = null;
element.addEventListener('mouseover', function () {
interval = setInterval(action, milliseconds);
});
element.addEventListener('mouseout', function () {
clearInterval(interval);
});
}
This starts the interval when the mouse is over the element and will call the action function every milliseconds. When the mouse leaves the element the repeated action will be stopped (until you hover the element again).
Just to show a simple application that counts the accumulated (complete) seconds you hovered an element:
function repeatWhileMouseOver(element, action, time) {
var interval = null;
element.addEventListener('mouseover', function() {
interval = setInterval(action, time);
});
element.addEventListener('mouseout', function() {
clearInterval(interval);
});
}
var counter = 1;
function count() {
console.log(counter++);
}
repeatWhileMouseOver(document.getElementById('over'), count, 1000);
#over {
border: 1px solid black;
}
<span id="over">Hover me (at least one second)!</span>
When you run the snippet note that it stops counting when you leave the element, but it resumes counting when you hover it again.
Maybe important to note that mouseout could also be replaced with mouseleave and similarly for mouseover and mouseenter. They will behave different if the element you attach the handler to has child elements.
Just a note about compatibility:
addEventListener is not supported in Internet Explorer 8 and before (see this Q+A for workarounds).
The mouseenter and/or mouseleave event are not supported (or supported correctly) in several old browsers. Check the notes about compatibility in case you have to support these (see for example this Q+A).
<script type="text/javascript">
var tId = null,
time = 100;
$( '#test' ).hover(
function( event ) {
tId = setTimeout( function() {
}, time);
},
function( event ) {
clearTimeout( tId );
}
)
</script>
<div id="test">test</div>
You should use setInterval() function here...
it also gives you the power to call the function in whatever time interval you desire
like: setInterval("a()",1000);
here the time is 1/1000 of a second so 1000 means 1 second
you can put this setInterval function in any function say b() and call the b() function from the div tag:
<div onmouseover="b()">
//
// try the timer factory
//
function timer ( callbacks, delay, fireNTimes ) {
timer._cb ||
( timer._cb = function () { return true; } );
return (function ( callbacks, delay, fireNTimes ) {
var
un,
timerState = {
'current-count' : 0,
'delay' : Math.abs( parseFloat( delay ) ) || 1000,
'repeat-count' : Math.abs( parseInt( fireNTimes ) ) || Number.POSITIVE_INFINITY,
'running' : false,
'interval' : un
},
callback = {
onTimer: callbacks.onTimer || timer._cb,
onStart: callbacks.onStart || timer._cb,
onStop : callbacks.onStop || timer._cb,
onEnd : callbacks.onEnd || timer._cb
};
return {
ctx: this,
startargs: [],
start: function ( /* callbacks_context, ...params */ ) {
var
that = this,
args = Array.prototype.slice.call( arguments, 1 );
( arguments[0] !== un ) && ( this.ctx = arguments[0] );
( args.length != 0 ) && ( this.startargs = args );
this.running() || (
timerState.running = true,
callback.onStart.apply( this.ctx, this.startargs ),
timerState['current-count'] += 1,
callback.onTimer.apply( this.ctx, this.startargs ),
( timerState['current-count'] == timerState['repeat-count'] ) &&
(
callback.onEnd.apply( this.ctx, this.startargs ),
( timerState["current-count"] = +( timerState.running = false ) ), true
) ||
( timerState.interval =
window.setInterval( function () {
timerState['current-count'] += 1;
callback.onTimer.apply( that.ctx, that.startargs );
( timerState['current-count'] == timerState['repeat-count'] ) &&
that.reset() &&
callback.onEnd.apply( that.ctx, that.startargs );
}, timerState.delay
)
)
);
return this;
},
stop: function () {
this.running() &&
(
window.clearInterval( timerState.interval ),
timerState.interval = un,
timerState.running = false,
callback.onStop.apply( this.ctx, this.startargs )
);
return this;
},
reset: function () {
return this.running() &&
( ! ( timerState["current-count"] = +( timerState.running = false ) ) ) &&
( window.clearInterval( timerState.interval ), true ) &&
( ( timerState.interval = un ), this );
},
currentCount: function () {
return timerState['current-count'];
},
delay: function () {
return timerState.delay;
},
repeatCount: function () {
return timerState['repeat-count'];
},
running: function () {
return timerState.running;
}
};
})( callbacks, delay, fireNTimes );
}
var
tm = timer(
{
onStart : function () { console.log( 'start:', 'this === ', this, arguments ); },
onTimer : function () { console.log( 'timer:', 'this === ', this, arguments ); },
onEnd : function () { console.log( 'done:', 'this === ', this, arguments ); },
onStop : function () { console.log( 'pause:', 'this === ', this, arguments ); }
},
2000
),
el = document.getElementById('btn1'),
o = { p1:'info' };
el.onmouseover = function () { tm.start( el, o ); };
el.onmouseout = function () { tm.stop(); };
//
//
// start: this === <button id="btn1"> [Object { p1="info"}]
// timer: this === <button id="btn1"> [Object { p1="info"}]
// timer: this === <button id="btn1"> [Object { p1="info"}]
// timer: this === <button id="btn1"> [Object { p1="info"}]
// pause: this === <button id="btn1"> [Object { p1="info"}]
//
// etc...
//
//
I think what you're looking for is actually the onmousemove event, it's a cleaner way to access the event object while you hover some element.
<script>
function a() {
"special code hear"
}
</script>
<div onmousemove( 'a()')> </div>
onmousemove event is called while you're hovering the element, check this example from W3 School.
And to understand more about this event, Mozilla docs covers much info about it.

Implementing jQuery plugin

I'm working on a jQuery plugin and already faced with interesting issue. Here is my code sample:
(function($){
var settings = {
'speed': 500
};
var methods = {
init: function(options){
settings = $.extend(options);
return this.each(function(){
$(this).bind('click.hideParagraph', methods.manage );
});
},
manage: function(){
if ($(this).hasClass("hidden")){
methods.show(this);
} else {
methods.hide(this);
}
},
show: function(item){
$(item).fadeIn(settings.speed, function(){});
},
hide: function(item){
$(item).fadeOut(settings.speed, function(){});
},
destroy: function(){
return this.each(function(){
$(this).unbind('click.hideParagraph');
});
}
};
$.fn.hideParagraph = function( method ) {
if ( methods[method] ) {
return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof method === 'object' || ! method ) {
return methods.init.apply( this, arguments );
} else {
$.error( 'Method ' + method + ' does not exist on jQuery.hideParagraph' );
}
};
})(jQuery);
The main problem is that functions fadeIn() and fadeOut() doesn't work this way (Error: f.speed is not a function in 'jquery.min.js'). Have anybody an idea why it happens?
And another question: is this the right way in implementing jQuery plugins? Could anyone suggest more convenient and flexible way?
Thanks.

$(document).ready() source

I need to wait for document readyness in my JavaScript, to insert a div at the bottom of the body.
I want to:
make this JavaScript file as small as possible (compile it down to < 1kb if possible)
inline the code that provides the document readyness in a closure (without exporting it)
Inlining the whole jQuery source in my file would be too big, so I'm looking for other methods. window.onload would work, but I specifically want document readyness, and not wait for the window.onload event.
Does anyone know a JS snippet that can do this? Or should I just copy part of jQuery's source?
EDIT:
I managed to crawl the jQuery source and put together with the following snippet:
var ready = (function () {
var ready_event_fired = false;
var ready_event_listener = function (fn) {
// Create an idempotent version of the 'fn' function
var idempotent_fn = function () {
if (ready_event_fired) {
return;
}
ready_event_fired = true;
return fn();
}
// The DOM ready check for Internet Explorer
var do_scroll_check = function () {
if (ready_event_fired) {
return;
}
// If IE is used, use the trick by Diego Perini
// http://javascript.nwbox.com/IEContentLoaded/
try {
document.documentElement.doScroll('left');
} catch(e) {
setTimeout(do_scroll_check, 1);
return;
}
// Execute any waiting functions
return idempotent_fn();
}
// If the browser ready event has already occured
if (document.readyState === "complete") {
return idempotent_fn()
}
// Mozilla, Opera and webkit nightlies currently support this event
if (document.addEventListener) {
// Use the handy event callback
document.addEventListener("DOMContentLoaded", idempotent_fn, false);
// A fallback to window.onload, that will always work
window.addEventListener("load", idempotent_fn, false);
// If IE event model is used
} else if (document.attachEvent) {
// ensure firing before onload; maybe late but safe also for iframes
document.attachEvent("onreadystatechange", idempotent_fn);
// A fallback to window.onload, that will always work
window.attachEvent("onload", idempotent_fn);
// If IE and not a frame: continually check to see if the document is ready
var toplevel = false;
try {
toplevel = window.frameElement == null;
} catch (e) {}
if (document.documentElement.doScroll && toplevel) {
return do_scroll_check();
}
}
};
return ready_event_listener;
})();
// TEST
var ready_1 = function () {
alert("ready 1");
};
var ready_2 = function () {
alert("ready 2");
};
ready(function () {
ready_1();
ready_2();
});
Thank you very much for helping me find this in the jQuery source. I can now put all this in a closure and do my work without exporting any functions and polluting the global scope.
One option would be to just get the core.js jQuery file from github.
You could probably slim it down quite a bit for code you don't need. Then run it through YUI compressor, and it should be pretty small.
http://github.com/jquery/jquery/blob/1.4.2/src/core.js (jQuery core)
http://yui.2clics.net/ (YUI compressor online)
I tried it, and this code worked properly:
$(function() {
var newDiv = document.createElement('div');
document.getElementsByTagName('body')[0].appendChild(newDiv);
});
Update: This was as small as I got it. It is entirely from jQuery and is around 1,278 bytes (compressed). Should get smaller when you gzip.
Only difference is that you need to call it like:
$.fn.ready(function() {
// your code
});
YUI Compressed:
(function(){var e=function(i,j){},c=window.jQuery,h=window.$,d,g=false,f=[],b;e.fn={ready:function(i){e.bindReady();if(e.isReady){i.call(document,e)}else{if(f){f.push(i)}}return this}};e.isReady=false;e.ready=function(){if(!e.isReady){if(!document.body){return setTimeout(e.ready,13)}e.isReady=true;if(f){var k,j=0;while((k=f[j++])){k.call(document,e)}f=null}if(e.fn.triggerHandler){e(document).triggerHandler("ready")}}};e.bindReady=function(){if(g){return}g=true;if(document.readyState==="complete"){return e.ready()}if(document.addEventListener){document.addEventListener("DOMContentLoaded",b,false);window.addEventListener("load",e.ready,false)}else{if(document.attachEvent){document.attachEvent("onreadystatechange",b);window.attachEvent("onload",e.ready);var i=false;try{i=window.frameElement==null}catch(j){}if(document.documentElement.doScroll&&i){a()}}}};d=e(document);if(document.addEventListener){b=function(){document.removeEventListener("DOMContentLoaded",b,false);e.ready()}}else{if(document.attachEvent){b=function(){if(document.readyState==="complete"){document.detachEvent("onreadystatechange",b);e.ready()}}}}function a(){if(e.isReady){return}try{document.documentElement.doScroll("left")}catch(i){setTimeout(a,1);return}e.ready()}window.jQuery=window.$=e})();
Full source (again, this is jQuery code):
(function() {
var jQuery = function( selector, context ) {
},
_jQuery = window.jQuery,
_$ = window.$,
rootjQuery,
readyBound = false,
readyList = [],
DOMContentLoaded;
jQuery.fn = {
ready: function( fn ) {
jQuery.bindReady();
if ( jQuery.isReady ) {
fn.call( document, jQuery );
} else if ( readyList ) {
readyList.push( fn );
}
return this;
}
};
jQuery.isReady = false;
jQuery.ready = function() {
if ( !jQuery.isReady ) {
if ( !document.body ) {
return setTimeout( jQuery.ready, 13 );
}
jQuery.isReady = true;
if ( readyList ) {
var fn, i = 0;
while ( (fn = readyList[ i++ ]) ) {
fn.call( document, jQuery );
}
readyList = null;
}
if ( jQuery.fn.triggerHandler ) {
jQuery( document ).triggerHandler( "ready" );
}
}
};
jQuery.bindReady = function() {
if ( readyBound ) {
return;
}
readyBound = true;
if ( document.readyState === "complete" ) {
return jQuery.ready();
}
if ( document.addEventListener ) {
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
window.addEventListener( "load", jQuery.ready, false );
} else if ( document.attachEvent ) {
document.attachEvent("onreadystatechange", DOMContentLoaded);
window.attachEvent( "onload", jQuery.ready );
var toplevel = false;
try {
toplevel = window.frameElement == null;
} catch(e) {}
if ( document.documentElement.doScroll && toplevel ) {
doScrollCheck();
}
}
};
rootjQuery = jQuery(document);
if ( document.addEventListener ) {
DOMContentLoaded = function() {
document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
jQuery.ready();
};
} else if ( document.attachEvent ) {
DOMContentLoaded = function() {
if ( document.readyState === "complete" ) {
document.detachEvent( "onreadystatechange", DOMContentLoaded );
jQuery.ready();
}
};
}
function doScrollCheck() {
if ( jQuery.isReady ) {
return;
}
try {
document.documentElement.doScroll("left");
} catch(e) {
setTimeout( doScrollCheck, 1 );
return;
}
jQuery.ready();
}
window.jQuery = window.$ = jQuery;
})();
I'm sure there are more bytes that could be removed.
Don't forget:
/*!
* jQuery JavaScript Library v1.4.2
* http://jquery.com/
*
* Copyright 2010, John Resig
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*/
There are several implementations for "DOMReady" functions but most that I can find seem a bit dated, so I don't know how they will behave with IE8 and such.
I would recommend using jQuery's ready() as I think it promises the most cross-browser compatibility. I'm not an expert in jQuery's source code, but this seems to be the right spot (lines 812-845 or search for function bindReady).
You can start with script: http://snipplr.com/view/6029/domreadyjs/, not optimized (but work) for latest Safari though (e.g. use timer instead of supported DOMContentLoaded).

Categories

Resources